当名称可能被修饰时使用 GetProcAddress

Bjö*_*ist 1 winapi calling-convention stdcall getprocaddress name-decoration

GetProcAddress()在 32 位 DLL 上使用的正确方法是什么?在 win32 上,共有三种调用约定,cdecl、stdcall 和 fastcall。如果 DLL 中的函数是foo他们将通过以下方式修饰名称_foo_foo@N并且@foo@N

但是如果 dll 的作者使用了 .def 文件,那么导出的名称将更改为“foo”,没有任何修饰。

这给我带来了麻烦,因为如果我想foo从使用 stdcall 的 dll加载,我应该使用装饰名称:

void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"_foo@16");
Run Code Online (Sandbox Code Playgroud)

或未装饰的:

void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"foo");
Run Code Online (Sandbox Code Playgroud)

? 我应该猜吗?我查看了很多 32 位 DLL 文件(stdcall 和 cdecl),它们似乎都导出了未修饰的名称。但是你能假设情况总是如此吗?

Dav*_*nan 5

这里真的没有捷径或确定的规则。您必须知道函数的名称。正常情况是您在编译时知道函数的名称。在这种情况下,导出的名称是否被破坏、修饰或实际上与语义名称完全无关都无关紧要。可以按顺序导出没有名称的函数。同样,您需要知道函数是如何导出的。

如果您看到一个库的头文件,并希望使用显式链接 ( LoadLibrary/ GetProcAddress)链接到它,那么您需要找出函数的名称。使用像 dumpbin 或 Dependency Walker 这样的工具来做到这一点。

现在,可能导致您提出问题的另一种情况是您在编译时不知道名称。例如,名称由程序的用户以一种或另一种方式提供。同样,要求用户知道函数的导出名称是非常合理的。

最后,您可以解析可执行文件的 PE 元数据以枚举其导出的函数。这将为您提供导出函数名称和导出函数序数的列表。这就是像 dumpbin 和 Dependency Walker 这样的工具所做的。