2

I have been looking for answers on how to reference unmanaged DLLs from C++,

Is there a better way to load a dll in C++?

DLL References in Visual C++

and it appears that a DLL cannot be loaded in C++ without the caller also having the .LIB file. Is this true that the .lib file is absolutely required if I want to dynamically load a DLL at run-time as follows?

   #include <Windows.h>
    HMODULE h;  
    LPCWSTR l;  
    DWORD error;
    wchar_t *myDLL = L"E:\\...\\myWin32DLL.dll";

    l = (LPCWSTR)myDLL;
    h = LoadLibrary(l);     
    error = GetLastError();  

If I call LoadLibrary using the code above, I get the result NULL. The error code from GetLastError() is 193: ERROR_BAD_EXE_FORMAT. Why?

EDIT/UPDATE: I figured out what's wrong -- I had the target platform of the program (that calls the DLL) as x64, and once I changed it to Win32, LoadLibrary now returns a non-NULL result.

The DLL is made up of one source file, expFns.cpp:

#include <Windows.h>

#define Pi 3.14159

extern _declspec(dllexport)  
double circumference(double radius)
{
    return 2.0 * radius * Pi;
}
BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpReserved )  // reserved
{
    return TRUE;
}

Here is how it is compiled:

cl expFns.cpp /link /DLL /out:mywin32dll.dll

If I use some well-known DLL such as unrar3.DLL, I still get error code 193. Why am I getting this error code?

On the other hand, if I use P/Invoke in managed C#, all I need is the full path to the .DLL, no .LIB file needed, and the function call to the DLL will work. Why is it necessary in C++ to have the .LIB file, but C# does not need the .LIB file?

[DllImport(@"E:\...\myDLL.dll"
            , CallingConvention = CallingConvention.Cdecl
            , EntryPoint = "get_value")]
internal static extern double get_value(double l, double w, double h);
Community
  • 1
  • 1
T. Webster
  • 9,605
  • 6
  • 67
  • 94

3 Answers3

5

LIB files are only needed if you want to link statically (forcing a strong dependency between your binary and the DLL: your binary won't load if the DLL isn't present). LoadLibrary() (or LoadLibraryEx()) bypasses all that: but on the other hand, you have to setup function pointers to all entry points using GetProcAddress() (or GetProcAddressEx()) with either the ordinal number of the exported function or its name, which can be a hassle. The latter is what C# does with DllImport, with a rather more friendly syntax.

Pontus Gagge
  • 17,166
  • 1
  • 38
  • 51
  • 2
    DLLs are not linked statically. They are linked dynamically. That's the 'D' in DLL. When you say "link statically" you mean implicit dynamic linking. Explicit dynamic linking is `GetProcAddress()`. – David Heffernan Apr 24 '11 at 17:11
  • Calling LoadLibrary using the full path to the DLL as shown above, I get the result NULL. Why am I getting NULL? Is there something my DLL is missing? – T. Webster Apr 24 '11 at 19:29
  • @David: in one respect the linking is 'like' static linking: the runtime loader will fixup all of the relocation records '_implicitely linked_' as you say, before even calling the entry point (and to make things worse: there is a sort of mixed mode called delay-load on windows, dunno where that fits in). – sehe Apr 24 '11 at 19:42
  • @David: you're technically correct, but for the purposes of loading a binary, it's a distinction without a difference. You don't have to carry the content of the DLL around in your binary, but in most other respect you have a static (immutable, closely coupled) relationship. – Pontus Gagge Apr 24 '11 at 20:25
  • @T Webster: most likely, your path doesn't point where you think it does. Try dropping the DLL in the same directory as your binary and load it without any directory prefix. If that works, you can check what your PATH environment variable contains and see if the loaded DLL should be in any of those directories (if you don't distribute it yourself). – Pontus Gagge Apr 24 '11 at 20:27
  • wait, I figured out what's wrong -- I had the target platform as x64, and once I changed it to Win32, it works. – T. Webster Apr 24 '11 at 20:44
2

Nope, you can call LoadLibrary and then GetProcAddress on any DLL at runtime - you only need the .LIB if you want to link against the DLL statically (i.e. just after compilation).

  • DLLs are not linked statically. They are linked dynamically. That's the 'D' in DLL. When you say "link statically" you mean implicit dynamic linking. Explicit dynamic linking is `GetProcAddress()`. – David Heffernan Apr 24 '11 at 17:12
  • @David Whatever. How about "checked for linkability at the stage when a true static link would take place"? But "statically" seems more convenient. –  Apr 24 '11 at 17:32
  • if I use LoadLibrary on myDLL as in the example shown, HMODULE h == NULL. The full path to the DLL is correct. Is LoadLibrary expected to return NULL here? I want to access the DLL dynamically and not statically. – T. Webster Apr 24 '11 at 19:27
  • @Webster Have you tried not using wide characters? If the DLL is successfully loaded, LoadLibrary should not return NULL. –  Apr 24 '11 at 19:40
  • The function requires LPCTSTR which wchar_t will convert to, but char* will not work. Could you show how to call LoadLibrary without using wide characters? http://msdn.microsoft.com/en-us/library/ms684175 – T. Webster Apr 24 '11 at 20:32
  • I figured out what's wrong -- I had the target platform as x64, and once I changed it to Win32, now LoadLibrary returns a non-NULL result. – T. Webster Apr 24 '11 at 20:47
2

The .lib is used for __declspec(dllexport) only, or Microsoft's C++ specific DLL import/export. P/Invoke is the same as .DEF files and uses GetProcAddress, which is C-style DLL import/export. The two are not interchangable.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • I doubt declspec(dllexport) has got much to do with this topic. Yes libs on windows will only contain exported business (you can do that on all UNIX-es too, but it's not the default). Also, I think that VC compiler will make you do the same for C-style linking (and you need to create the .def file for the DLL entries) – sehe Apr 24 '11 at 19:44
  • @sehe: `declspec(dllexport)` is the compiler directive that causes you to need it. And VC will definitely not make you create a .def file for it. `__declspec(dllexport)` is automated dynamic linking- you mark the functions/etc you need, you link to the lib, and it's done. – Puppy Apr 24 '11 at 21:07