Visual c++ 当我只提供未修饰的名称时,修饰的名称如何进入导入库? 我在VisualC++,VS2015社区工作。我已经编写了这个小小的DLL: #包括“stdafx.h” int showMsgBox(wchar\u t*标题,wchar\u t*消息) { MessageBox(空,消息,标题,0); 返回0; }

Visual c++ 当我只提供未修饰的名称时,修饰的名称如何进入导入库? 我在VisualC++,VS2015社区工作。我已经编写了这个小小的DLL: #包括“stdafx.h” int showMsgBox(wchar\u t*标题,wchar\u t*消息) { MessageBox(空,消息,标题,0); 返回0; },visual-c++,dllexport,Visual C++,Dllexport,还有这个小小的客户: #include "stdafx.h" __declspec(dllimport) int showMsgBox(wchar_t* caption, wchar_t* message); int main() { showMsgBox(L"SimpleDLLClient", L"Hello DLL World!"); return 0; } 为了导出showMsgBox函数,我创建了以下模块定

还有这个小小的客户:

#include "stdafx.h"

__declspec(dllimport) int showMsgBox(wchar_t* caption, wchar_t* message);

int main()
{
    showMsgBox(L"SimpleDLLClient", L"Hello DLL World!");
    return 0;
}
为了导出showMsgBox函数,我创建了以下模块定义文件:

LIBRARY SimpleDLL

EXPORTS
    showMsgBox
LIBRARY SimpleDLL

EXPORTS
    ?showMsgBox@@YAHPEA_W0@Z
当我链接我的客户机时,我将链接DLL时创建的导入库传递给它。一切都很好

这让我很困惑

根据,“Visual C++编译器使用C++函数的名称修饰,必须使用修饰名作为内名或内名,或者在源代码中使用Extn”C定义导出函数。 但我不是在输出一个装饰过的名字,是吗

如果我不使用模块定义文件,而是使用_declspec(dllexport)extended属性作为函数的前缀,我不会感到惊讶(因为编译器应用的任何名称修饰都应该与编译器应用于客户机的相同修饰相匹配)

同样,如果我在DLL和客户机代码中都在函数前面加上'extern“C',这也应该起作用(它确实起作用了:我测试了它),因为,同样,符号应该匹配

但是,当DLL和客户机代码都不使用“extern”C时,我本来希望模块定义文件中的未修饰导出无法解析客户机对同一未修饰名称的引用,这似乎也是MSDN所期望的。然而,通过模块定义文件导出未修饰的名称确实有效,即使我没有在任何地方使用“extern”C

有人能告诉我为什么这样做吗

更新 查看链接器创建的文件,我发现将未修饰的名称放入模块定义文件显然会导致修饰名称包含在导入库中。当我在该文件上使用dumpbin/exports时,我得到的结果如下:

文件类型:库

     Exports

       ordinal    name

                  ?showMsgBox@@YAHPEA_W0@Z (int __cdecl showMsgBox(wchar_t  *,wchar_t *))
现在,有点令人惊讶(无论如何,对我来说),如果我明确地给装饰过的名字加上别名,比如:

LIBRARY SimpleDLL

EXPORTS
    showMsgBox=?showMsgBox@@YAHPEA_W0@Z
dumpbin告诉我这就是导入库中显示的内容:

File Type: LIBRARY

     Exports

       ordinal    name

                  showMsgBox
如果我在声明导入的函数时使用'extern“C',则在构建客户端时将其用作链接器的输入也可以正常工作:

extern "C" int showMsgBox(wchar_t* caption, wchar_t* message);
这是有道理的,因为链接器现在寻找的符号是未修饰的“showMsgBox”,我将该符号别名为编译DLL时创建的修饰名称

太好了

在我看来,一页又一页的MSDN文档都说必须在模块定义文件中使用修饰名,这是错误的。相反,如果您在模块定义文件中使用未修饰的名称,则实际合并到导入库中的修饰名称将解析对编译客户机代码时构造的匹配修饰名称的引用。当然,这是我更喜欢的,而不是必须提取修饰名称并在模块定义文件中使用它们。它只是与MSDN页面反复说的不匹配

我喜欢认为我是一个聪明的孩子,但如果有人说微软不知道自己的产品是如何工作的,那就太傲慢了

我错过了什么

更新2 由于DLL和客户机都使用修饰名称(也就是说,在任何地方都不使用“extern”C),所以在模块定义文件中使用未修饰的名称可以很好地构建一切,正如我所说的。但是,有趣的是,如果我在模块定义文件中使用修饰名称,那么在对源代码没有任何更改的情况下,构建工作同样出色:

LIBRARY SimpleDLL

EXPORTS
    showMsgBox
LIBRARY SimpleDLL

EXPORTS
    ?showMsgBox@@YAHPEA_W0@Z

在二进制级别,它创建的导入库与我在模块定义文件中使用未修饰名称时创建的库几乎相同。唯一的区别似乎是时间戳,除了靠近末尾的一个字节。仍在试图理解这一点,但似乎更确定的是,链接器以某种方式导出了修饰名称,即使模块定义文件仅引用了未修饰的名称。

也许这只是一种未记录的行为?我同意。定义文件的文档是完全错误的。这只是一个具有1-800支持电话号码的链接器的行为。是相关的。我不确定Raymond声称使用EXPORTS会在其未混合名称下公开函数的说法是否正确。使用dumpbin,我看到导出showMsgBox和导出?showMsgBox@@YAHPEA_W0@Z两者实际上都合并了?showMsgBox@@YAHPEA_W0@Z导入到导入库中,这解释了为什么客户端代码未成功使用“extern”C链接。导入库确实将损坏的名称标记为名称类型“name”,将未混合的名称标记为名称类型“undecorate”,但两者实际上都包含损坏的版本,并且不会链接到未混合的客户端(使用“extern”C“)。也许这只是一种未记录的行为?我同意。定义文件的文档是完全错误的。这只是一个具有1-800支持电话号码的链接器的行为。是相关的。我不确定Raymond声称使用EXPORTS会在其未混合名称下公开函数的说法是否正确。使用dumpbin,我看到导出showMsgBox和导出?showMsgBox@@YAHPEA_W0@Z两者实际上都合并了?showMsgBox@@YAHPEA_W0@Z导入到导入库中,这解释了为什么客户端代码未成功使用“extern”C链接。导入库确实将损坏的名称标记为名称类型“name”,将未混合的名称标记为名称类型“undecorate”,但两者实际上都包含损坏的版本,并且不会链接到未混合的客户端(使用“extern”C”的客户端)。