我有一个 .Net Framework 4.8 应用程序,我需要在其中将一些 html/css 转换为 pdf。
我已经采样了一个 DinkToPdf 的演示项目,它是“.NET Core P/Invoke wrapper for wkhtmltopdf library that uses Webkit engine to convert HTML pages to PDF”。这在 .NET 核心应用程序和 Xamarin Forms 应用程序中有效,但无法在 .Net Framewrk 应用程序中运行。
我已通过 NugetPackageManager 将 DinkToPDF v1.0.8 添加到我的项目的参考文件夹中。我查看了包依赖项并确保所有版本都达到所需版本。由于 DinkToPdf 使用它,我需要将一个本机库复制到我的项目根目录:libwkhtmltox.dll(我尝试过不同版本)我也尝试过 RndUsr0.DinkToPdf 包,它“升级到 .NET Standard 2.0, .NET Core 2.1,wkhtmltopdf v0.12.5。” 但没有更好的结果。
会发生什么:当我的应用调用 basicConverter.Converet(HtmlToPdfDocument doc) 时出现异常:"DinkToPdf.WkHtmlToXBindings::wkhtmltopdf_init' 使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查PInvoke 签名的调用约定和参数与目标非托管签名匹配。"
public static void ConvertToPdf(/*string [] args*/)
{
//load native lib libwkhtmltox.dll
var architectureFolder = (IntPtr.Size == 8) ? "64 bit" : "32 bit";
var wkHtmlToPdfPath = Path.Combine(AppContext.BaseDirectory, $"wkhtmltox\\v0.12.4\\{architectureFolder}\\libwkhtmltox.dll");//here a libwkhtmltox.dll needs to be stored
IntPtr pDll = NativeMethods.LoadLibrary(wkHtmlToPdfPath);
if (pDll == IntPtr.Zero)
{
throw new FileNotFoundException("-- Cannot load libwkhtmltox == a dll used for html to pdf convertion --");
}
var converter = new BasicConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
}
};
ObjectSettings objectSettings = new ObjectSettings()
{
PagesCount = true,
HtmlContent = html,
WebSettings = { DefaultEncoding = "utf-8"}
};
doc.Objects.Add(objectSettings);
byte[] pdf = converter.Convert(doc);//!!! THIS IS THE POINT THAT THROWS UP
string outputFile = Path.Combine(AppContext.BaseDirectory, "ImageFromHtmnl.pdf");
using (FileStream stream = new FileStream(outputFile, FileMode.Create))
{
stream.Write(pdf, 0, pdf.Length);
}
}
总结一下:我希望带有 libwkhtmltox.dll 本机库的 DinkToPdf nuget 包在 .NET Framework 应用程序中的功能与在 .NET Core 应用程序中的功能一样。但事实并非如此。
我错过了什么?
编辑:忘记发布实现对本机库的调用的此类:
static class NativeMethods
{
[DllImport("kernel32.dll"/*, CallingConvention = CallingConvention.Cdecl*/)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
public static string GetLibraryPathname(string filename)
{
// If 64-bit process, load 64-bit DLL
bool is64bit = System.Environment.Is64BitProcess;
string prefix = "Win32";
if (is64bit)
{
prefix = "x64";
}
var lib1 = prefix + @"\" + filename;
return lib1;
}
}