在32位DLL上使用GetProcAddress()
的正确方法是什么?在win32上,有三个调用约定,cdecl,stdcall和fastcall。如果DLL中的函数为foo
,则它们将按以下方式装饰名称_foo
,_foo@N
和@foo@N
。
但是如果dll的作者使用了.def文件,则导出的名称将更改为“foo”而不进行任何修饰。
这给我带来麻烦,因为如果我想从使用stdcall的dll加载foo
,我应该使用装饰名称:
void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"_foo@16");
或未修饰的那个:
void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"foo");
?我该猜吗?我看了很多32位DLL文件(stdcall和cdecl),它们似乎都导出了未修饰的名称。但你能否认为总是的情况?
答案 0 :(得分:4)
这里真的没有捷径或明确的规则。您必须知道该功能的名称。正常情况是您在编译时知道函数的名称。在这种情况下,导出的名称是否被修改,修饰或者实际上与语义名称完全无关并不重要。可以按顺序导出无名称的函数。同样,您需要知道函数是如何导出的。
如果您看到一个库的头文件,并希望通过显式链接(LoadLibrary
/ GetProcAddress
)链接到它,那么您需要找到该函数的名称。使用像dumpbin或Dependency Walker这样的工具来做到这一点。
现在,可能导致您提出问题的另一种情况是您在编译时不知道该名称。例如,名称由程序用户以某种方式提供。同样,要求用户知道函数的导出名称是非常合理的。
最后,您可以解析可执行文件的PE元数据以枚举其导出的函数。这将为您提供导出的函数名称和导出的函数序列的列表。这就是dumpbin和Dependency Walker之类的工具。
答案 1 :(得分:0)
如果编译时使用了__declspec(dllexport)
,头文件中使用了__declspec(dllimport)
,以及extern "c"
,那么这些函数不需要修饰。 __declspec
有助于使用未修饰的名称,但函数重载、命名空间和类仍然需要相同的方式来区分它们。
通常,面向对象的函数是使用函数序数而不是它们的修饰名称导出的。将序数转换为 (char*)(unsigned short)ordinal
,因此,GetProcAddress(module, (char*)(unsigned short)ordinal);
编辑:虽然大多数 Windows 使用 UTF-16,但 GetProcAddress 使用 UTF-8,因此它不能使用宽字符串。
GetProcAddress(module, L"foo")
等同于 GetProcAddress(module, "f");