0

我使用过“CPPLoadLibrary”示例(来自 Microsoft All-in-One 框架) 好的,有两种方法可以从示例 DLL 中导出符号。

  1. 使用 .DEF 文件从 DLL 导出符号 模块定义 (.DEF) 文件是一个文本文件,其中包含一个或多个描述 DLL 各种属性的模块语句。创建 .DEF 文件并在构建 DLL 时使用 .def 文件。使用这种方法,我们可以按序号而不是按名称从 DLL 中导出函数。
  2. 使用 __declspec(dllexport) 从 DLL 导出符号 __declspec(dllexport) 将导出指令添加到目标文件,因此我们不需要使用 .def 文件。在尝试导出修饰的 C++ 函数名称时,这种便利最为明显。

所以我们有以下代码。

typedef int     (_cdecl* LPFNGETSTRINGLENGTH1)      (PCWSTR);
typedef int     (CALLBACK* LPFNGETSTRINGLENGTH2)    (PCWSTR);

LPFNGETSTRINGLENGTH1 lpfnGetStringLength1 = (LPFNGETSTRINGLENGTH1) 
    GetProcAddress(hModule, "GetStringLength1");

LPFNGETSTRINGLENGTH2 lpfnGetStringLength2 = (LPFNGETSTRINGLENGTH2) 
    GetProcAddress(hModule, "_GetStringLength2@4");

所以我的问题是如何确定符号的名称以便调用 GetProcAddress?在第一种情况下,它非常简单,我们从 .DEF 文件中获取符号名称。但是“_GetStringLength2@4”又是什么下划线呢?“@4”代表什么?谢谢。

4

2 回答 2

3

如果您不使用 .DEF 文件,导出名称将根据其调用约定进行修饰,以支持导出重载函数。请参阅为什么我不能 GetProcAddress 我 dllexport'ed 的函数?

[T]装饰方案因建筑而异,因调用约定而异。因此,例如,如果函数是从 PPC DLL 导出的,则必须这样做GetProcAddress(hinst, "..SomeFunction"),但如果它是从 80386 DLL 导出的,则extern "C" __stdcall需要GetProcAddress(hinst, "_SomeFunction@8"),但如果是,则__fastcall需要GetProcAddress(hinst, "@SomeFunction@8")

更重要的是,C++ 装饰因编译器供应商而异。如果使用 Microsoft C++ 编译器编译,则可能需要 C++ 导出函数GetProcAddress(hinst, "?SomeFunction@@YGXHH@Z"),但如果使用 Borland C++ 编译器编译,则可能需要一些其他修饰字符串。

因此,如果您希望人们能够GetProcAddress使用函数并且您希望您的代码可移植到多个平台,或者如果您希望他们能够使用 C/C++ 以外的语言使用您的 DLL,或者使用不同于 C/C++ 的 C++ 编译器Microsoft Visual Studio,那么您必须按其未修饰的名称导出该函数。

有关各种名称装饰方案的描述,请参阅调用约定的历史,第 3 部分。在这种情况下,该函数使用__stdcall调用约定,因此通过添加下划线和@符号以及它所采用的参数的字节数来修饰它。它需要一个字大小的参数,总共 4 个字节,所以它被修饰为_GetStringLength2@4.

于 2013-10-02T17:07:29.290 回答
-1

要回答您的实际问题,请使用编译器的 TDUMP 或类似工具,或任何其他可以显示可执行文件导出表的工具,以便您查看实际导出的名称。

于 2013-10-02T17:24:44.013 回答