CW Win32 x86 - Newbie can't get off the ground making a dll, please help!

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CW Win32 x86 - Newbie can't get off the ground making a dll, please help!

4,304 Views
mphillips
Contributor I
Hello,

I've been at it for about a week now and gone through every manual and internet resource I could find, but I still don't know what I'm doing wrong.  (Windows XP on a Dell Inspiron 640m, CW 5.0.0.)  I can't get rid of this error:

Error   : Undefined symbol: '_mysum' referenced from '_main' in hello.c:19
hello.c line 19  

'mysum' is a function defined in a DLL I created from the CW template, and is called from hello.c.  This is happening in the simplest possible program I can write, so it's possible to describe what I'm doing literally screen by screen:

Making the DLL:
1. New project => Win 32 C++ Stationery, project name ‘testutils’
2.
Choose Win32 DLL: DLL using default libraries
3. Project testutils.mcp is now created, with the file
'x86_Win32 DLL.cpp' in the source directory. 
4. I add the definition for 'mysum' to x86_Win32 DLL.cpp', and put the definition in the header.  This compiles s without problem, creating “testutils Release.dll” and “testutils Release.lib”.  I've put the code for these functions at the end of the message.

Making hello.c:
1. New project =>
Win 32 C Stationery, project name ‘test_cw’
2. Choose Win32 Console App: App using default libraries
3. Project test_cw.mcp is now created, with the file 'hello.c' in the source directory. 
4
. a) Add call to ‘mysum’ in function main, b) add #include "x86_Win32 DLL.h", c) add directory testutils to access path.

Doing all of this results in the error I showed above, and *only* this error.  I've tried a number of variations of this, like putting mysum in a separate file, but I always get the above linker error OR a variation thereof which has something like (@X@ANNN@Y) following the reference to _mysum--sorry I didn't save this but I presume that when you use CW's DLL template, your functions are supposed to go in the cpp file it creates?  Anyway I would be immensely grateful if someone could shed light on this, I really couldn't find a how-to anywhere in the documentation or elsewhere.

Best,
Matt

/*******************************hello.c**************************************/
#include "x86_Win32 DLL.h"
#include <stdio.h>

int main(void)
{
    double d;
   
    d = mysum(2,3);
   
    fprintf(stdout, "Hello World, 2 + 3 = %f!\n", d);
    return 0;
}
/*********************************************************************/


/***********************************
x86_Win32 DLL.h**********************/
#ifndef __X86_WIN32_DLL_H__
#define __X86_WIN32_DLL_H__

#ifndef IMPEXP
#define IMPEXP    __declspec(dllimport)
#endif

IMPEXP int RectFrame(HDC hdc, int x1, int y1, int x2, int y2, int t);
IMPEXP int EllipseFrame(HDC hdc, int x1, int y1, int x2, int y2, int t);

#endif /*#ifndef __X86_WIN32_DLL_H__*/

double mysum(double a, double b);
/*********************************************************************/


/****************************************x86_Win32 DLL.cpp*****************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

/*    Declare our exports, defining IMPEXP only inside the DLL */
#define IMPEXP    __declspec(dllexport)
#include "x86_Win32 DLL.h"

/*    This DLL user entry point function is only required when your application
    has special initialization or termination requirements.  Otherwise
    the MSL runtime provides the appropriate startup code.  */
BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved );

BOOL WINAPI DllMain( HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved )
{
    char buf[512];
    char exename[256];
    char dllname[256];
   
    GetModuleFileName(0L, exename, sizeof(exename));
    GetModuleFileName(hInst, dllname, sizeof(dllname));
       
    switch(fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            snprintf(buf, sizeof(buf), "Process\n'%s'\nattaching to\n'%s'...", exename, dllname);
            MessageBox ( GetFocus(), buf, "Notice", MB_OK|MB_SYSTEMMODAL );
            return 1;

        case DLL_PROCESS_DETACH:
            snprintf(buf, sizeof(buf), "Process\n'%s'\ndetaching from\n'%s'...", exename, dllname);
            MessageBox ( GetFocus(), buf, "Notice", MB_OK|MB_SYSTEMMODAL );
            return 1;

        default:
            return 1;
       }
       return 0;
}

IMPEXP int RectFrame(HDC hdc, int x1, int y1, int x2, int y2, int t)
{
    Rectangle(hdc, x1, y1, x2, y2);
    Rectangle(hdc, x1+t, y1+t, x2-t, y2-t);
    return 1;
}

IMPEXP int EllipseFrame(HDC hdc, int x1, int y1, int x2, int y2, int t)
{
    Ellipse(hdc, x1, y1, x2, y2);
    Ellipse(hdc, x1+t, y1+t, x2-t, y2-t);
    return 1;
}

double mysum(double a, double b) {
    return(a+b);
    }
/*********************************************************************/

--
Alban Edit: Please always include CodeWarrior version in Message Subject line.




Message Edited by Alban on 2007-09-28 08:18 PM
Labels (1)
0 Kudos
6 Replies

592 Views
J2MEJediMaster
Specialist I
Thanks for posting your code. Looking at it, what seems to jump out to me as that you need to declare your functon as so:

Code:
IMPEXP double mysum(double a, double b);

Without that IMPEXP macro, the compiler/linker thinks your mysum function is a private function, and as a consequence it's invisible to main(). Look at the example graphic functions in the sample DLL code, and how the IMPEXP macro makes them visible to code outside of the DLL.

---Tom

0 Kudos

592 Views
mphillips
Contributor I
Hi Tom,

Thank you very much for responding to my query.  I did in fact figure out eventually what 'IMPEXP' was, but adding it doesn't help.  In fact, even the example functions won't work!  Here is the error message I got when I tried to call RectFrame from hello.c:

Error   : Undefined symbol: '__declspec(dllimport) _RectFrame (__imp__RectFrame)'
referenced from '_main' in hello.c:20
hello.c line 20  

Of course, the linker is seeing the declaration in the header file--I'm not getting a 'function has no prototype' error--but it can't access the definition.  I've included the code which produced the above error below--only hello.c has been modified from what CW provides as example code.

It has occurred to me that since what I'm trying to link to is a dll and not just another .cpp file I want compiled, that the linker should be told to access the actual .lib file--"testutils Release.lib", which is generated in the testutils directory.  However scouring the 'Settings' panel I have found no place to specify this linkage.  I'm really at a loss at this point, please let me know any ideas you might have.

Best,
Matt


/**********************************************************hello.c****************************************/
#include <stdio.h>
#include "x86_Win32 DLL.h"

int main(void)
{
    HDC hdc;
    int d;
   
    d = RectFrame(hdc, 1,2,3,4,5);
//    d = mysum(2,3);
   
    fprintf(stdout, "Hello World, d = !\n", d);
    return 0;
}
/***********************************************************************************************************/


/*****************************************************x86_Win32 DLL.cpp, unmodified example code*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

/*    Declare our exports, defining IMPEXP only inside the DLL */
#define IMPEXP    __declspec(dllexport)
#include "x86_Win32 DLL.h"

/*    This DLL user entry point function is only required when your application
    has special initialization or termination requirements.  Otherwise
    the MSL runtime provides the appropriate startup code.  */
BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved );

BOOL WINAPI DllMain( HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved )
{
    char buf[512];
    char exename[256];
    char dllname[256];
   
    GetModuleFileName(0L, exename, sizeof(exename));
    GetModuleFileName(hInst, dllname, sizeof(dllname));
       
    switch(fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            snprintf(buf, sizeof(buf), "Process\n'%s'\nattaching to\n'%s'...", exename, dllname);
            MessageBox ( GetFocus(), buf, "Notice", MB_OK|MB_SYSTEMMODAL );
            return 1;

        case DLL_PROCESS_DETACH:
            snprintf(buf, sizeof(buf), "Process\n'%s'\ndetaching from\n'%s'...", exename, dllname);
            MessageBox ( GetFocus(), buf, "Notice", MB_OK|MB_SYSTEMMODAL );
            return 1;

        default:
            return 1;
       }
       return 0;
}

IMPEXP int RectFrame(HDC hdc, int x1, int y1, int x2, int y2, int t)
{
    Rectangle(hdc, x1, y1, x2, y2);
    Rectangle(hdc, x1+t, y1+t, x2-t, y2-t);
    return 1;
}

IMPEXP int EllipseFrame(HDC hdc, int x1, int y1, int x2, int y2, int t)
{
    Ellipse(hdc, x1, y1, x2, y2);
    Ellipse(hdc, x1+t, y1+t, x2-t, y2-t);
    return 1;
}
/***********************************************************************************************************/


/*****************************************************x86_Win32 DLL.h, unmodified example code*/
#ifndef __X86_WIN32_DLL_H__
#define __X86_WIN32_DLL_H__

#ifndef IMPEXP
#define IMPEXP    __declspec(dllimport)
#endif

IMPEXP int RectFrame(HDC hdc, int x1, int y1, int x2, int y2, int t);
IMPEXP int EllipseFrame(HDC hdc, int x1, int y1, int x2, int y2, int t);

#endif /*#ifndef __X86_WIN32_DLL_H__*/

/***********************************************************************************************************/






0 Kudos

592 Views
CompilerGuru
NXP Employee
NXP Employee
In general, as you might have read in other forum entries, the x86 technology was sold to Nokia.
About your particular problem, you either did not export the names,
use
www.dependencywalker.com
to verify that,
or you did not add the *.lib to your project. Just add it to the project as you add *.c files.

Daniel

0 Kudos

592 Views
mphillips
Contributor I
Hello Daniel,

Thank you for suggestions, and telling me about DependencyWalker.  When I ran DW on the dll (which I renamed 'testutils.dll' for consistency with the .cpp, .h files), I did get a warning, which turns out to be precisely what is described here near the top of the DW FAQ:

Q: Why am I seeing a lot of applications where MPR.DLL shows up in red under SHLWAPI.DLL because it is missing a function named WNetRestoreConnectionA? I also get a "Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module" message. A: Some versions of SHLWAPI.DLL (like the one on Windows XP) have a delay-load dependency on the function WNetRestoreConnectionA in MPR.DLL. Missing delay-load functions are not a problem as long as the calling DLL is prepared to handle the situation. Dependency Walker flags all potential problems as it cannot detect if an application intends to handle the issue. In the case of SHLWAPI.DLL, this is not an problem as it does not require WNetRestoreConnectionA to exist and handles the missing function at runtime. This warning can be ignored. See the "How to Interpret Warnings and Errors in Dependency Walker" section in help for more details.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Specifically, I got the warning mentioned in the Q., MPR.DLL showing up in red, etc.  I'm not sure what the  'calling DLL' is here, but it sounds like I can ignore this?  Or does this mean I have to add something to my DLL?  If so what?  Anyway, this was the only warning/error I received.  DW 'sees' the functions that are defined in the .cpp file, viz. RectFrame and EllipseFrame--they are listed in one of the panels. 

I also have added the .lib file to the project, but this didn't help--I get the same error as before, except now it says 'Link error' instead of just 'error'.  Just to be sure, here it is:

Link Error   : Undefined symbol: '__declspec(dllimport) _RectFrame (__imp__RectFrame)'
referenced from '_main' in hello.c

Thank you for your help, and please let me know any further suggestions you might have (particularly in regard to the DW output).  I guess I'll start trying my luck with the Nokia boards too...  aargh!

Best,
Matt


0 Kudos

592 Views
CompilerGuru
NXP Employee
NXP Employee
I did not notice before as I was looking at the DLL specific part, but now I saw that the
DLL code is in C++ and you user app is in C. Well, if you do not prepare the C++ header file for this,
then that just wont work together, regardless is you use the two sources files over a DLL boundary or if you link them directly together. If you have a C++ header file which has to support to be included from a C source file, you have to add the folling snippets.
To the start, after the multiple inclusion macro,

#ifdef __cplusplus
extern "C" {
#endif

and to the end of the header, after all declarations:

#ifdef __cplusplus
}
#endif

Google for that, I saw that so often, I sure the web is full of matches :smileyhappy:.

Ignore the MPR.DLL failure with dependency walker, Microsoft knows how to handle delay loading. Actually when using DW you can see if the exported functions are using C++ name mangling, if so then they cannot be used with C.

Daniel

PS: Still the wrong forum :smileyhappy:
0 Kudos

592 Views
mphillips
Contributor I
Hello Daniel,

Nice observation!  I had been dimly aware of the extern C requirement but thought, wrongly, it wouldn't be required for CW which understands C and C++.  The user app is in C because eventually, when I have these issues sorted out, I will have to write it in C.  With your change, the code compiled just fine.

UNFORTUNATELY, the program doesn't *run*.  It is a simple console app, and the window flashes open and closes after about 1 frame.  Here is the code:

Code:
#include <stdio.h>#include "testutils.h"int main(void){ int d; char key = '\0'; char instr[256];  d = 9; d = mysum(2,3);  fprintf(stdout, "Hello World, d = %d!\n", d); while (key != 'q') {  scanf("%s", instr);  key = instr[0]; } return 0;}

 If I comment out the call to mysum, the console window stays open and prints the message until 'q' is entered, like it's supposed to.  When I tried to debug it, I got the following in the "Log":

DLL not found at address 0x7C964ED1
DLL not found at address 0x7C964ED1

NB it is printed twice every time I run the debugging routine.  In the 'Stack' window of the debugger, there is the following:

0x7C93F8FB( ntdll.dll )
0x7C964ED1( ntdll.dll )

And in the window that contains code, just Assembler.  When I try to step, it just quits out of the debugger.  NB I have tried adding not just the .lib file but also the .dll file to the project, along with the .h file, but it doesn't matter.

I can taste victory but not quite there yet!  Thanks for your help thus far and please let me know if you have any ideas about where to take it from here.

BTW wrong forum?  This should go to Nokia?  What can I say, Metrowerks is where the 'help' button on my version of CW takes me...

Best,
Matt

0 Kudos