在名称可能被装饰时使用GetProcAddress

时间:2015-08-31 12:40:43

标签: winapi calling-convention stdcall getprocaddress name-decoration

在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),它们似乎都导出了未修饰的名称。但你能否认为总是的情况?

2 个答案:

答案 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");