找不到链接库问题

微软抓包工具 NetworkMonitor,自带 SDK,包括头文件和库文件。开发中,用到了这个工具。像往常一样,在代码中包含头文件,在链接选项中添加库文件,但是链接一直出错,提示找不到函数定义。

1>Linking...
 unresolved external symbol _NmCloseHandle@4 referenced in function 
 unresolved external symbol _NmCreateFrameParser@12 referenced in function
 unresolved external symbol _NmAddProperty@12 referenced in function 
 unresolved external symbol _NmConfigConversation@12 referenced in function 
 unresolved external symbol _NmCreateFrameParserConfiguration@16 referenced
 unresolved external symbol _NmLoadNplParser@20 referenced in function 
 unresolved external symbol _NmGetPropertyValueById@32 referenced in 
 unresolved external symbol _NmGetPropertyInfo@12 referenced in function
 unresolved external symbol _NmParseFrame@24 referenced in function _wmain
 unresolved external symbol _NmGetFrame@12 referenced in function _wmain
 unresolved external symbol _NmGetFrameCount@8 referenced in function _wmain

是否没有连接到指定文件 NmApi.lib?

代码里用了 #pragma comment(lib, "NmApi.lib") 来指定链接库,没有指定具体目录,是否目录不对?把 NmApi.lib 换了几个目录,没有解决问题。

修改链接方式,在工程的 Link 选项中指定链接文件,带上指定目录,还是不行。试着修改 lib 文件名称,会提示没有找到,说明链接文件是找到了,但是没有找到对应函数实现。

是否头文件或链接库有问题?

检查头文件,用了 extern C 说明接口调用是 C 风格的。lib 文件里有否有对应函数的定义呢,用 dumpblin 查看,显示结果是有定义的。

E:\code\test\TestNmApi\TestNmApi>dumpbin /exports NmApi.lib
Microsoft (R) COFF/PE Dumper Version 14.00.23026.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file NmApi_x64.lib

File Type: LIBRARY

     Exports

       ordinal    name

                  NmAddDriverCaptureFilter
                  NmAddField
                  NmAddFilter
                  NmAddFrame
                  NmAddOlpBlockToFilter
                  ...
                  NmSetNplProfileAttributeByGuid
                  NmStartCapture
                  NmStopCapture

 Summary

         BD .debug$S
         14 .idata$2
         14 .idata$3
          8 .idata$4
          8 .idata$5
          A .idata$6

是否头文件与库文件函数的 name mangling 不对应?

注意到头文件中,函数前都加了修饰符 WINAPI,定义为 __stdcall,不同的修饰符会使用不同的 namemangling,尝试将 WINAPI 重新定义为 __fastcall __cdecl,都不行。__stdcall 的 name mangling 会在函数前加下划线 ,而 lib 库的导出函数并没有下划线!找到问题了,怎么解决呢?

从 DLL 重新生成 LIB

函数定义已经在那里了,只是 lib 定义不对,那么重新生成 liib 是否可以解决问题?从 stackoverflow 上找来一段脚本,可以从 dll 生成 lib 文件。

dumpbin /exports sqlite3.dll > exports.txt
echo LIBRARY SQLITE3 > sqlite3.def
echo EXPORTS >> sqlite3.def
for /f "skip=19 tokens=4" %A in (exports.txt) do echo %A >> sqlite3.def

lib /def:sqlite3.def /out:sqlite3.lib /machine:x86

很顺利地生成了 lib 文件,dumpbin 查看 lib 导出函数,name mangling 也对了,函数前都加上了下划线。启动链接程序,还是出错。发现 name mangling 还是略有不同,导出函数的名称不带参数个数,尝试把 WINAPI 定义为空,再次启动链接,链接成功。但是运行程序直接就崩溃了。

原来是 64 位程序问题

无计可施了,对比 NetMonitor 安装文件,突然注意到有 64 位和 32 位之分。马上想到安装的 64 位版本,而我编译的是 32 位版本,问题应该就在这个。32 位版本在这台 PC 上无法安装,用 7-zip 解压,得到了对应的 lib 文件。再次链接调试,终于成功了。原来 64 位程序的 name mangling 是不带修饰符的。