调用非托管dll文件的方法
之前在做xx工具的时候,引用到一个叫XZ.NET的库,但是这个库需要用到liblzma.dll的文件,这个由于是使用C++编写的,因此没有办法直接打包到可执行文件中,那么如果要打包成单文件需要嵌入调用liblzma.dll的时候该如何解决呢?
解决这个方法有两种: - 第一种是可以将这类dll文件释放到临时目录中再通过DllImport调用,不过这个方法不太优雅,有一些问题不好处理; - 第二种是利用costura.fody去处理这类dll文件调用的问题
如果使用第二种方法,流程如下:
- 需要安装
costura.fody - 将
liblzma.dll放在Costura32或Costura64文件夹中,如果不存在这样的文件夹需要手动创建,至于放在哪个文件夹,是根据dll库的版本以及需要编译出来的可执行文件的类型来定 - 编写
FodyWeavers.xml,内容如下XML如果在第2步的时候你将dll文件放在<?xml version="1.0" encoding="utf-8"?> <Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> <Costura> <Unmanaged32Assemblies> liblzma </Unmanaged32Assemblies> </Costura> </Weavers>Costura64文件夹中,需要将Unmanaged32Assemblies改成Unmanaged64Assemblies编译一下,这个dll文件就被集成进去了
备注
如果确定这个dll库被编译进去了?有两种判断方法: 1. 检查文件是否变大,不过有些情况下无法准确确定 2. 通过dnSpy等工具反编译检查
可以看到,编译后的liblzma变成了costura.liblzma.dll,这样也可以确定liblzma被编译进去了
- 如果需要调用这个dll文件,需要通过DllImport导入,参考代码如下 C#
class Demo { const string DllName = "liblzma.dll"; [DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName); public void Test() { IntPtr libHandle = LoadLibrary(dllPath); if (libHandle == IntPtr.Zero) { Console.WrileLine("无法导入liblzma.dll"); return; } // } }
备注
每个dll库的调用方法可能会有所区别,具体请参考对应的项目文档和源码去编写