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



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

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

如果你有一个库的头文件,并且想要用显式链接(LoadLibrary/GetProcAddress)链接到它,那么你需要找出函数的名称。使用像dumpbin或Dependency Walker这样的工具来完成。

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

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

如果在编译过程中使用__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");相同

最新更新