2

我一直在寻找有关如何从 C++ 引用非托管 DLL 的答案,

有没有更好的方法在 C++ 中加载 dll?

Visual C++ 中的 DLL 引用

如果调用者也有.LIB文件,似乎无法在 C++ 中加载 DLL 。如果我想在运行时动态加载 DLL,那么 .lib 文件是否是真的,如下所示?

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

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

如果我使用上面的代码调用 LoadLibrary,我得到的结果是 NULL。GetLastError() 的错误代码是 193: ERROR_BAD_EXE_FORMAT。为什么?

编辑/更新: 我发现出了什么问题——我将程序的目标平台(调用 DLL)设置为 x64,一旦我将其更改为 Win32,LoadLibrary 现在返回一个非 NULL 结果。

DLL 由一个源文件 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;
}

以下是它的编译方式:

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

如果我使用一些众所周知的 DLL,例如 unrar3.DLL,我仍然会收到错误代码 193。为什么我会收到此错误代码?

另一方面,如果我在托管 C# 中使用 P/Invoke,我只需要 .DLL 的完整路径,不需要 .LIB 文件,并且对 DLL 的函数调用将起作用。为什么在 C++ 中必须要有 .LIB 文件,而 C# 不需要 .LIB 文件?

[DllImport(@"E:\...\myDLL.dll"
            , CallingConvention = CallingConvention.Cdecl
            , EntryPoint = "get_value")]
internal static extern double get_value(double l, double w, double h);
4

3 回答 3

5

仅当您想要静态链接时才需要 LIB 文件(在二进制文件和 DLL 之间强制建立强依赖关系:如果 DLL 不存在,您的二进制文件将不会加载)。LoadLibrary()(or LoadLibraryEx()) 绕过了所有这些:但另一方面,您必须使用GetProcAddress() (或GetProcAddressEx()) 使用导出函数的序号或其名称来设置指向所有入口点的函数指针,这可能很麻烦。后者是 C# 对 . 所做的DllImport,具有更友好的语法。

于 2011-04-24T16:49:33.573 回答
2

不,您可以在运行时在任何 DLL 上调用 LoadLibrary,然后调用 GetProcAddress - 如果您想静态链接到 DLL(即在编译之后),您只需要 .LIB。

于 2011-04-24T16:49:40.167 回答
2

.lib 仅用于__declspec(dllexport)或 Microsoft 的 C++ 特定 DLL 导入/导出。P/Invoke 与 .DEF 文件相同,使用 GetProcAddress,即 C 风格的 DLL 导入/导出。两者不可互换。

于 2011-04-24T17:00:56.617 回答