views:

247

answers:

3

I started studying DLL's with implicit linking. I don't really fully understand how it works. Please correct me where I'm wrong. I failed to compile the next code(3 modules):

MyLib.h

#ifdef MYLIBAPI

#else


#define MYLIBAPI extern "C" __declspec(dllimport)

#endif


MYLIBAPI int g_nResult;

MYLIBAPI int Add(int nLeft, int nRight);

As far as I understand this is the header of the DLL. #define MYLIBAPI extern "C" __declspec(dllimport) means that here we are going to declare some functions/variables that will be described in devoted .cpp file and will be contained in a DLL.

MyLibFile1.cpp

#include <windows.h>

#define MYLIBAPI extern "C" __declspec(dllexport)

#include "MyLib.h"

int g_nResult; 
int Add(int nLeft, int nRight) {
   g_nResult = nLeft + nRight;
   return(g_nResult);
}

So, this is obviously the file where our functions are implemented. This is the part of the DLL, right?

MyExeFile1.cpp

#include <windows.h>
#include <strsafe.h>
#include <stdlib.h>

#include "MyLib.h"

int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) {

   int nLeft = 10, nRight = 25;

   TCHAR sz[100];
   StringCchPrintf(sz, _countof(sz), TEXT("%d + %d = %d"),
      nLeft, nRight, Add(nLeft, nRight));
   MessageBox(NULL, sz, TEXT("Calculation"), MB_OK);

   StringCchPrintf(sz, _countof(sz),
      TEXT("The result from the last Add is: %d"), g_nResult);
   MessageBox(NULL, sz, TEXT("Last Result"), MB_OK);
   return(0);
}

So, this is the executable file where we use the functions from the library. The whole thing doesn't work. I tried to put this all into one directory and compile at once. I tried first to compile a DLL from the first two modules(successfully) and then compile the executable (changing the path to the header file). However it resulted in 2 errors both times:

error LNK2019: unresolved external symbol WinMain@16 referenced in function __tmainCRTStartup

\Visual Studio 2008\Projects\MyExeFile1\Debug\MyExeFile1.exe : fatal error LNK1120: 1 unresolved externals

What' s the correct way to do that - what should I change in the code and how should I compile the code (I use VS2008)? Thanks.

+1  A: 

Change _tWinMain to WinMain in MyExeFile1.cpp. It is looking for your entry point to be named WinMain not _tWinMain and so the linker is complaining that it can't find WinMain.

There are project settings that determine what name the entry point function should be, but I'm not sure which one would require _tWinMain.

Edit According to this posting, _tWinMain is a define that maps to WinMain if you include tchar.h.link text

shf301
`_tWinMain` is likely to be a define expanded based on `_UNICODE` setting of your project.
Dmitry
Wow, you are right. I switched _tWinMain to WinMain and included tchar separetely, so it worked. I don't understand why there was a "1 unresolved external" error, which I was more concerned about. But anyway, thanks!
lhj7362
A: 

Does it even compile? Shouldn't you #include <tchar.h> for all TCHAR types and definitions to work?

Dmitry
It doesn't compile because of other error. It seems that including strsafe.h is enough. EDIT: probably _tWinMain includes tchar.
lhj7362
`_tWinMain` is _defined_ in tchar.h, it can _not_ include tchar.h :)
Dmitry
+1  A: 

#include <tchar.h> to solve the linker error.

Your header file should look like this:

#ifdef BUILDING_DLL
#  define MYLIBAPI extern "C" __declspec(dllexport)
#else
#  define MYLIBAPI extern "C" __declspec(dllimport)
#endif

MYLIBAPI int __stdcall Add(int nLeft, int nRight);

Right-click your DLL project in Solution Explorer, Properties, C/C++, Preprocessor, Preprocessor Definitions, add "BUILDING_DLL". Repeat for the Release configuration.

You can verify that your DLL properly exports the functions with Dumpbin.exe /exports.

The __declspec(dllimport) declarator is not strictly necessary, it does however make it more efficient. The __stdcall attribute is not necessary either, it does however make your DLL usuable from any language that supports calling DLL exports.

Hans Passant
Thanks.. I don't truely understand what happens. If I add a preprocessor definition, when is BUILDING_DLL defined and when not? What's the purpose of it? I think it like this: while the DLL is not compiled, the BUILDING_DLL is not defined, so we are importing the functions into DLL and after that out? ... (I now see that I don't understand the dllimport/dllexport parts at all)
lhj7362
It is #defined when you add the preprocessor definition. You did so in the DLL project, which ensures the function gets exported. It is not defined in any other project, which ensures the function gets imported.
Hans Passant