如何将Pdfium等依赖DLL嵌入程序?Costura.Fody未生效问题
问题分析与解决方案
为什么Costura.Fody没生效?
Costura.Fody确实能自动打包托管DLL,但对于Pdfium.dll这种非托管原生DLL,需要额外配置才能正确处理,另外还有几个常见坑:
- 你可能没在
FodyWeavers.xml中明确指定要打包的非托管DLL,Costura默认不会自动识别所有非托管文件 - Pdfium分x86/x64架构版本,如果你的项目没有针对特定架构编译,或者Costura没配置对应架构的DLL,打包后运行时会找不到匹配的版本
- 若你是手动引用的
PdfiumViewer.dll而非通过NuGet安装,Costura可能没正确识别到这个托管DLL的引用关系
解决方案
方案1:修复Costura.Fody的配置
这是最省心的方式,只要正确配置就能让Costura自动打包并加载这两个DLL:
- 确保安装了最新版的
Costura.FodyNuGet包 - 在项目根目录创建或修改
FodyWeavers.xml,添加非托管DLL的架构配置:
<Weavers> <Costura> <!-- 指定32位和64位的Pdfium.dll --> <Unmanaged32Assemblies>pdfium</Unmanaged32Assemblies> <Unmanaged64Assemblies>pdfium</Unmanaged64Assemblies> <!-- 托管的PdfiumViewer.dll会自动被打包,无需额外配置 --> </Costura> </Weavers>
- 检查你的
Pdfium.dll(分x86/x64版本)是否放在项目对应的架构目录下(比如x86和x64子文件夹),并且它们的复制到输出目录属性设置为始终复制 - 重新编译项目,现在Costura会把对应架构的Pdfium.dll和PdfiumViewer.dll都打包进exe,运行时自动加载
方案2:手动嵌入并提取DLL(不依赖Costura)
如果Costura还是不好用,可以手动控制DLL的嵌入和加载:
- 把
Pdfium.dll(分x86/x64)和PdfiumViewer.dll添加到项目中,在属性里设置生成操作为嵌入的资源 - 在程序启动的
Main方法中,先提取并加载非托管的Pdfium.dll,再处理托管的PdfiumViewer.dll:
using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; class Program { [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); static void Main(string[] args) { // 判断当前进程架构,加载对应版本的Pdfium.dll var is64Bit = Environment.Is64BitProcess; var pdfiumResourceName = is64Bit ? "YourProjectName.x64.pdfium.dll" : "YourProjectName.x86.pdfium.dll"; // 提取Pdfium.dll到临时目录 var tempPdfiumPath = Path.Combine(Path.GetTempPath(), "pdfium.dll"); using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(pdfiumResourceName)) { if (resourceStream == null) throw new FileNotFoundException("未找到嵌入的Pdfium.dll资源", pdfiumResourceName); using (var fileStream = new FileStream(tempPdfiumPath, FileMode.Create, FileAccess.Write)) { resourceStream.CopyTo(fileStream); } } // 加载Pdfium.dll LoadLibrary(tempPdfiumPath); // 加载托管的PdfiumViewer.dll(如果需要) var viewerResourceName = "YourProjectName.PdfiumViewer.dll"; using (var viewerStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(viewerResourceName)) { if (viewerStream == null) throw new FileNotFoundException("未找到嵌入的PdfiumViewer.dll资源", viewerResourceName); var viewerBytes = new byte[viewerStream.Length]; viewerStream.Read(viewerBytes, 0, viewerBytes.Length); Assembly.Load(viewerBytes); } // 后续正常启动你的程序逻辑 } }
注意替换代码中的YourProjectName为你的实际项目名称,确保资源路径和嵌入的资源名称一致。
方案3:使用PdfiumViewer的官方NuGet包
如果你之前是手动引用的DLL,建议卸载手动引用,直接安装PdfiumViewer NuGet包——它会自动管理不同架构的Pdfium.dll,再配合Costura.Fody的配置,大概率能直接解决打包问题,无需手动处理架构和路径。
内容的提问来源于stack exchange,提问作者derekantrican
相关产品推荐
相关产品推荐

