Ins*_*oop 5 c dll name-mangling
我需要将一些 Delphi 代码重写为 C++,并且我们需要链接到动态库TMLComm2004.dll。事实证明,我们没有任何.lib文件,因此我们决定使用以下命令行生成它:
dumpbin /EXPORTS C:\Users\fayard\Desktop\TMLComm2004.dll > C:\Users\fayard\Desktop\TMLComm2004.txt
Run Code Online (Sandbox Code Playgroud)
我们得到如下文件
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C:\Users\fayard\Desktop\TMLComm2004.dll
File Type: DLL
Section contains the following exports for TMLcomm.dll
00000000 characteristics
401F6AD5 time date stamp Tue Feb 3 10:33:09 2004
0.00 version
1 ordinal base
27 number of functions
27 number of names
ordinal hint RVA name
1 0 00001122 _MSK_COFFDownloadFlash@16
2 1 0000114F _MSK_COFFDownloadRAM@20
3 2 0000106E _MSK_CheckSum@12
4 3 00001172 _MSK_CloseComm@0
5 4 00001190 _MSK_GetActiveBoard@4
6 5 0000109B _MSK_GetBoardInfo@8
7 6 0000104B _MSK_GetBytesCountInQueue@0
8 7 0000119A _MSK_GetChar@4
9 8 000010E6 _MSK_GetCharNoWait@4
10 9 000011A4 _MSK_GetCommBaudRate@4
11 A 000010DC _MSK_GetHostBoard@4
12 B 0000108C _MSK_OpenComm@16
13 C 000011DB _MSK_ReceiveData@16
14 D 000011CC _MSK_ReceiveMessage@4
15 E 0000105A _MSK_RegisterReceiveUnsolicitedMsgHandler@4
16 F 000011AE _MSK_ResetMSKBoard@0
17 10 00001037 _MSK_SendChar@4
18 11 000010EB _MSK_SendData@16
19 12 0000126C _MSK_SendMessage@4
20 13 0000128F _MSK_SetActiveBoard@4
21 14 00001136 _MSK_SetB0BlockAsData@4
22 15 0000100A _MSK_SetBoardBaudRate@4
23 16 00001019 _MSK_SetCharMode@4
24 17 00001168 _MSK_SetCommBaudRate@4
25 18 00001050 _MSK_SetDebugWindow@8
26 19 00001276 _MSK_SetHostBoard@4
27 1A 00001046 _MSK_UpdateCommTimeouts@0
Summary
C000 .data
3000 .idata
6000 .rdata
4000 .reloc
21000 .rsrc
3E000 .text
2000 shdata
Run Code Online (Sandbox Code Playgroud)
然后,我们编辑了该TMLComm2014.txt文件并将其更改为.def删除了@xx的文件。该文件如下所示:
EXPORTS
_MSK_COFFDownloadFlash
...
Run Code Online (Sandbox Code Playgroud)
然后,我们生成一个.lib文件:
lib /def:C:\Users\fayard\Desktop\TMLComm2004.def /out:C:\Users\fayard\Desktop\TMLComm2004.lib
Run Code Online (Sandbox Code Playgroud)
我们编译如下程序:
extern "C" {
bool MSK_OpenComm(unsigned char a, unsigned short b, bool c, unsigned char d);
}
...
Run Code Online (Sandbox Code Playgroud)
当我们编译并链接 时.lib,我们得到一个错误:
LNK2019 unresolved external symbol _MSK_OpenComm referenced in function...
Run Code Online (Sandbox Code Playgroud)
我的做法有什么问题吗?
更新
我已经成功编译:
extern "C" {
bool __stdcall MSK_OpenComm(unsigned char a, unsigned short b, bool c, unsigned char d);
}
Run Code Online (Sandbox Code Playgroud)
但现在问题出在链接时。我很困惑,因为从命令行,我有:
==================================================
dumpbin /headers TMLComm.lib
Version : 0
Machine : 14C (x86)
TimeDateStamp: 5964C365 Tue Jul 11 14:24:05 2017
SizeOfData : 00000022
DLL name : TMLComm2004.dll
Symbol name : __MSK_OpenComm@16
Type : code
Name type : no prefix
Hint : 11
Name : _MSK_OpenComm@16
==================================================
dumpbin /exports TMLComm.dll
12 B 0000108C _MSK_OpenComm@16
==================================================
Run Code Online (Sandbox Code Playgroud)
现在编译一切正常,但问题出在链接时:
link tmlcomm.obj Motor.obj main.obj TMLComm.lib /out:main.exe
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
tmlcomm.obj : error LNK2019: unresolved external symbol _MSK_OpenComm@16 referenced in function "bool __cdecl msk_opencomm(unsigned char,unsigned short,bool,unsigned char)" (?msk_opencomm@@YA_NEG_NE@Z)
Teclis.exe : fatal error LNK1120: 1 unresolved externals
Run Code Online (Sandbox Code Playgroud)
小智 1
查看 Microsoft 的修饰名称文档。对于 C,前导下划线和尾随@<number>表示stdcall调用约定,这与标准cdecl.
因此,您应该修改符号以 结尾的所有函数的声明@<number>:
extern "C" {
__stdcall bool MSK_OpenComm(unsigned char a, unsigned short b, bool c, unsigned char d);
}
Run Code Online (Sandbox Code Playgroud)
我不确定是否要剥离@<number>从.def文件中删除该部分是否是正确的做法,我对此表示怀疑,但只是尝试一下。
根据我使用MinGWs 工具创建.def文件(gendef)的实验, 中的名称.def不应包含前导下划线,但应包含@<number>末尾部分。因此对于这个示例函数,.def应该具有以下行:
MSK_OpenComm@16
Run Code Online (Sandbox Code Playgroud)
手动创建这些所需文件的替代方法是使用附带的工具MinGW. 您可以执行以下操作:
extern "C" {
__stdcall bool MSK_OpenComm(unsigned char a, unsigned short b, bool c, unsigned char d);
}
Run Code Online (Sandbox Code Playgroud)
根据您的评论,您可能需要手动编辑该.def文件gendef以包含如下行:
MSK_OpenComm@16=_MSK_OpenComm@16
Run Code Online (Sandbox Code Playgroud)
看来gendef可能会混淆,因为 dll 导出意外的修饰名称。
当使用导入库时,这将具有“静态存根”,其名称类似于 DLL 的实际导出符号,但带有__imp__前缀。为了解决这个问题,您的声明中还需要另一个属性:
extern "C" {
__declspec(dllimport) __stdcall bool MSK_OpenComm(unsigned char a, unsigned short b, bool c, unsigned char d);
}
Run Code Online (Sandbox Code Playgroud)