Whistlle

M.J

关于DllImport的踩坑记录

最近在编译某开源项目时需要在c#工程里面调用非托管c艹dll,结果不管怎么搞都是DllNotFoundException。然后作者用TravisCi倒是运行的好好地。折腾了2天现在来总结一下:

不是真正的DllNotFound

找不到函数入口签名等等都算在内,统称NotFound。检查方法也很简单,dumpbin看一下就好了。注意要用VS自带的Tool  Command Prompt:

dumpbin

由于c艹导出的时候extern C了,所以无需指定入口,dll里面各函数名字也是正确的。

dll缺少依赖

dll依赖的dll也要一并复制到bin下面,然而有时候缺少的是某些系统的库文件,不知道是哪个漏了,这就尴尬了。好在有Dependency Walker

zlib

少了个zlib,如果由于项目是使用命令行自动编译的,懒得多写一个copy,而且万一以后有依赖了什么dll又要copy太烦了。干脆一起打包进一个dll:

在C艹项目中:使用静态链接编译dll(项目属性->配置属性->C/C++->代码生成->运行时库), 将MD选项改为MT. 使用MT选项生成的dll文件大小更大。

改了以后在使用上述软件Zlib不显示了,然而问题还是没有解决。

真的NotFound

找不到dll也分为两种:找不到文件和文件名不对。MSDN上对这两者的说明并不多,最后看Mono文档的时候发现了问题所在。我就直接摘录文档了:

Windows DLL Search Path

  1. The directory from which the application loaded.
  2. The current directory
  3. The system directory. Use the GetSystemDirectory() function to get the path of this directory.
  4. The 16-bit system directory.
  5. The Windows directory. Use the GetWindowsDirectory() function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

dll名字

文档中对dll名字的说明就是在[DllImport(“”)]中写入的字符串是文件名去除平台后缀+平台前缀的剩余部分。譬如一个工程名为 cocoshit_2.0.0,在win下就是cocoshit_2.0.0.dll,linux下为libcocoshit_2.0.0.so, mac下是 libcocoshit_2.0.0.dylib,而写进代码中只要[DllImport(“cocoshit”)]即可,DllImport为自动添加前后缀。

道理我也知道啊!代码里面也是这么写的,就指望这个跨平台呢!

然而我注意了文档后面还有一段话:

Note: Windows will not automatically append a .dll extension to library names that already have a period (.) in their name, such aslibgtk-win32-2.0-0.dll. If you try to use libgtk-win32-2.0-0 as the library name, Windows won’t automatically append .dll, resulting in a DllNotFoundException. Consequently you should either avoid periods in library names or always use the full filename (including the.dll extension) and rely on Mono’s <dllmap/> mechanism.

???

        你是说在有 点 的情况下windows平台下就不会自动添加.dll后缀?什么?这也太智障了吧,项目加点命名成项目.子项目这种情况太常见了吧,所以遇到这要就一定要填入后缀全称?然后用#if之流分平台多写几行恶心的代码?或者如Mono文档中给出的解决方案写一个dllmap?WTF。

于是通篇加.dll测试一下问题解决,就是不加后缀这个问题。之后估计写个issue向作者反映一下这个问题或者干脆在linux下部署持续集成运行项目绕过这个问题算了。

 

7 + 5 =

回到顶部