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++?
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);
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()(orLoadLibraryEx()) bypasses all that: but on the other hand, you have to setup function pointers to all entry points using GetProcAddress() (orGetProcAddressEx()) with either the ordinal number of the exported function or its name, which can be a hassle. The latter is what C# does withDllImport, with a rather more friendly syntax.