'Loading wkhtmltopdf DLL (`wkhtmltox.dll`) on Windows
I have installed wkhtmltopdf using the Windows installer and am using the wkhtmltopdf crate. wkhtmltopdf is installed at C:\Program Files\wkhtmltopdf, which contains (among other things) bin/wkhtmltox.dll and lib/wkhtmltox.lib.
I have successfully gotten Rust to link the .lib at build time with the following build.rs:
fn main() {
#[cfg(windows)]
{
println!("cargo:rustc-link-search=C:/Program Files/wkhtmltopdf/lib");
println!("cargo:rustc-link-lib=dylib=wkhtmltox");
}
}
That (I think) works fine for building; at least, it appears to build successfully (and without this build.rs, it fails to build). For running, I've tried using the windows crate to load the DLL at runtime as follows:
#[tokio::main]
async fn main() -> LSResult<()> {
println!("starting main");
#[cfg(windows)]
{
println!("cfg(windows)");
use windows::{
core::PCSTR,
Win32::{
Foundation::HANDLE,
System::LibraryLoader::{
AddDllDirectory, LoadLibraryExA, SetDefaultDllDirectories,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
},
},
};
// Add the wkhtmltopdf DLL path to the DLL search path
let dll_path = r#"C:\Program Files\wkhtmltopdf\bin\wkhtmltox.dll"#;
let dll_path_pcstr_bytes = dll_path
.bytes()
.chain(std::iter::once(0))
.collect::<Vec<_>>();
unsafe {
LoadLibraryExA(
PCSTR(dll_path_pcstr_bytes.as_ptr() as *const u8),
HANDLE(0),
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
);
}
}
println!("about to get pdf");
wkhtmltopdf::PdfApplication::new().expect("Failed to init PDF application");
println!("got pdf");
}
But, try as I might, I cannot get the DLL to be loaded at runtime. I always get the following error at runtime:
error: process didn't exit successfully: target\\debug\\my_crate.exe (exit code: 0xc0000135, STATUS_DLL_NOT_FOUND)
C:/Users/me/.cargo/bin/cargo.exe: error while loading shared libraries: ?: cannot open shared object file: No such file or directory
None of the println! statements are executed; as soon as cargo run starts running the executable, the STATUS_DLL_NOT_FOUND is thrown. To me this indicates that Rust is trying to load the DLL before main is even called, and failing because it's not on the default DLL search path.
If I comment out the line wkhtmltopdf::PdfApplication::new().expect("Failed to init PDF application"); then it runs fine, everything is printed, etc. So it seems I have to find a way to point the executable to the DLL before even running it!
Also, after installing wkhtmltopdf on my Mac, things "just worked" without needing to do any explicit loading of the dylib. I assume this is because the Mac installation places the shared libraries in a standard location, whereas the Windows installation does not. But on Windows I cannot customize the installation of wkhtmltopdf; rather I must somehow point the executable to the DLL, and seemingly must do so before main is called.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
