C++中的GetProcAddress函数

24

大家好:我已经将我的DLL加载到项目中,但每当我使用GetProcAddress函数时,它都返回NULL!我该怎么办?我在“MYDLL.dll”中使用此函数(double GetNumber(double x))。

这是我使用的代码:

typedef double (*LPGETNUMBER)(double Nbr);
HINSTANCE hDLL = NULL;
LPGETNUMBER lpGetNumber;
hDLL = LoadLibrary(L"MYDLL.DLL");
lpGetNumber = (LPGETNUMBER)GetProcAddress((HMODULE)hDLL, "GetNumber");

2
那个函数是从 DLL 中导出的吗? - sharptooth
5
在命令提示符中尝试使用“dumpbin /exports mydll.dll”命令,以查看您的dll中导出名称是什么。您可以通过VS获取dumpbin,或者从MS作为平台SDK的一部分免费获取。 - Fozi
还有一个名为depends.exe(或Dependency Walker)的GUI工具,它可以显示您的DLL导出的所有函数。 - Boaz Yaniv
1
@Alireza:如果GetProcAddress()返回null,则意味着Windows无法在DLL中找到该入口点。也没有理由转换hDLL变量,LoadLibrary()返回一个HMODULE,这是GetProcAddress()的第一个输入参数。 - Lucky Luke
1
@Lucky Luke:重新表述你的话:在非石器时代的系统中,HINSTANCE和HMODULE是相同的(http://blogs.msdn.com/b/oldnewthing/archive/2004/06/14/155107.aspx)。 - Boaz Yaniv
显示剩余5条评论
3个回答

54

检查返回值并调用GetLastError()将使您更加安全。在这里,您应该检查返回代码两次。实际上,您没有检查返回代码。

hDLL = LoadLibrary(L"MYDLL.DLL");

检查hDLL。它是否为NULL?如果是,则调用GetLastError()以找出原因。可能只是简单的“文件未找到”。

lpGetNumber = (LPGETNUMBER)GetProcAddress((HMODULE)hDLL, "GetNumber");
如果 lpGetNumber 是 NULL,调用 GetLastError()。它会告诉你为什么无法找到过程地址。有几种可能的情况:
  1. 没有导出名为 GetNumber 的函数。
  2. 有一个导出的名为 GetNumber 的函数,但它没有标记为 extern "c",导致名称重整
  3. hDLL 不是有效的库句柄。
如果是上面的情况 #1,你需要通过在声明中装饰使用 __declspec(dllexport) 导出函数,像这样:

MyFile.h

__declspec(dllexport) int GetNumber();

如果是上述情况#2,你需要做以下操作:

extern "C"
{
  __declspec(dllexport) int GetNumber();
};

第二个提示对我非常有效!我原以为你只需要 extern "C" 或者 __declspec(dllexport) 中的一个,但事实证明你需要两个都要... - Chef Pharaoh
现在为什么我无法获取类函数的地址呢?1)它需要是静态成员吗?2)它可以在命名空间内吗? - Chef Pharaoh
@ChefPharaoh:你同样可以访问类成员。但是,你必须在调用GetProcAddress时提供装饰名称。不幸的是,这个答案没有解释如何使用装饰名称。 - IInspectable
非常感谢,我也遇到了这个问题。 - BattleTested_закалённый в бою
1
我的解释正确吗?C++编译器可能会更改int GetNumber();的名称(作为名称重整技术)。因此,如果发生这种情况,声明和定义将不匹配(特别是在使用外部库时)。因此,我们在其中添加extern "C",以便编译器将此部分视为C语言(在C语言中没有名称重整和函数重载)。顺便说一句,extern "c"通常用于库,对吗? - BattleTested_закалённый в бою

4
您可能需要检查您的 GetNumber 函数是否作为一个 __stdcall 函数导出。
如果是这样,请尝试使用 GetProcAddress(hDLL, "_GetNumber@N");,其中 NGetNumber 参数列表中所有字节的总数。例如,如果您的函数签名是 int GetNumber(int a, double b),则其在 DLL 中的真实名称将是 _GetNumber@12
参考:__stdcall

3
很可能是 LoadLibrary() 失败了。你看不到这个错误,因为显然你没有检查它的返回值:

如果函数失败,则返回值为NULL。要获取扩展的错误信息,请调用GetLastError。

编辑: 我们不知道您如何在DLL代码中导出该函数,但此线程解释了GetProcAddress失败的一些原因。

我检查了LoadLibrary,它没有返回NULL。只有GetProcAddress返回了NULL。 - Alireza
我假设您知道如何在DLL中创建和导出符号。如果不知道,请查看此教程:http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855 或者这个:http://www.programmers-corner.com/tutorial/4 - karlphillip
你的源代码有些误导性。将来你可能想修复它,因为这会对你有利。 - karlphillip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接