链接到不带 .lib 的 .dll 文件

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)