1

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

或未装饰的:

void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"foo");

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

4

2 回答 2

5

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

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

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

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

于 2015-08-31T12:59:35.917 回答
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");

于 2021-03-27T01:27:53.483 回答