From e36e1e1fbb35f80850e672eeba51a9ac0ee954d5 Mon Sep 17 00:00:00 2001 From: adumbidiot Date: Fri, 30 Oct 2020 18:24:19 -0700 Subject: [PATCH] Copy win_delay_load_hook from Neon --- napi/Cargo.toml | 3 ++ napi/src/lib.rs | 2 + napi/src/win_delay_load_hook.rs | 79 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 napi/src/win_delay_load_hook.rs diff --git a/napi/Cargo.toml b/napi/Cargo.toml index ab9a8357..0628c8fb 100644 --- a/napi/Cargo.toml +++ b/napi/Cargo.toml @@ -18,6 +18,9 @@ tokio_rt = ["futures", "tokio", "once_cell"] [dependencies] napi-sys = {version = "0.4", path = "../sys"} +[target.'cfg(windows)'.dependencies] +winapi = "0.3.9" + [dependencies.encoding_rs] optional = true version = "0.8" diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 8ce80c4e..442194de 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -110,6 +110,8 @@ mod tokio_rt; #[cfg(all(feature = "libuv", napi4))] mod uv; mod version; +#[cfg(target_os = "windows")] +mod win_delay_load_hook; pub use napi_sys as sys; diff --git a/napi/src/win_delay_load_hook.rs b/napi/src/win_delay_load_hook.rs new file mode 100644 index 00000000..712cbc54 --- /dev/null +++ b/napi/src/win_delay_load_hook.rs @@ -0,0 +1,79 @@ +//! The following directly was copied from [neon][]. +//! +//! Rust port of [win_delay_load_hook.cc][]. +//! +//! When the addon tries to load the "node.exe" DLL module, this module gives it the pointer to the +//! .exe we are running in instead. Typically, that will be the same value. But if the node executable +//! was renamed, you would not otherwise get the correct DLL. +//! +//! [neon]: https://github.com/neon-bindings/neon/blob/5ffa2d282177b63094c46e92b20b8e850d122e65/src/win_delay_load_hook.rs +//! [win_delay_load_hook.cc]: https://github.com/nodejs/node-gyp/blob/e18a61afc1669d4897e6c5c8a6694f4995a0f4d6/src/win_delay_load_hook.cc + +use std::ffi::CStr; +use std::ptr::null_mut; +use winapi::shared::minwindef::{BOOL, DWORD, FARPROC, HMODULE, LPVOID}; +use winapi::shared::ntdef::LPCSTR; +use winapi::um::libloaderapi::GetModuleHandleA; + +// Structures hand-copied from +// https://docs.microsoft.com/en-us/cpp/build/reference/structure-and-constant-definitions + +#[repr(C)] +#[allow(non_snake_case)] +struct DelayLoadProc { + fImportByName: BOOL, + // Technically this is `union{LPCSTR; DWORD;}` but we don't access it anyways. + szProcName: LPCSTR, +} + +#[repr(C)] +#[allow(non_snake_case)] +struct DelayLoadInfo { + /// size of structure + cb: DWORD, + /// raw form of data (everything is there) + /// Officially a pointer to ImgDelayDescr but we don't access it. + pidd: LPVOID, + /// points to address of function to load + ppfn: *mut FARPROC, + /// name of dll + szDll: LPCSTR, + /// name or ordinal of procedure + dlp: DelayLoadProc, + /// the hInstance of the library we have loaded + hmodCur: HMODULE, + /// the actual function that will be called + pfnCur: FARPROC, + /// error received (if an error notification) + dwLastError: DWORD, +} + +#[allow(non_snake_case)] +type PfnDliHook = unsafe extern "C" fn(dliNotify: usize, pdli: *const DelayLoadInfo) -> FARPROC; + +const HOST_BINARIES: &[&[u8]] = &[b"node.exe", b"electron.exe"]; + +unsafe extern "C" fn load_exe_hook(event: usize, info: *const DelayLoadInfo) -> FARPROC { + if event != 0x01 + /* dliNotePreLoadLibrary */ + { + return null_mut(); + } + + let dll_name = CStr::from_ptr((*info).szDll); + if !HOST_BINARIES + .iter() + .any(|&host_name| host_name == dll_name.to_bytes()) + { + return null_mut(); + } + + let exe_handle = GetModuleHandleA(null_mut()); + + // PfnDliHook sometimes has to return a FARPROC, sometimes an HMODULE, but only one + // of them could be specified in the header, so we have to cast our HMODULE to that. + exe_handle as FARPROC +} + +#[no_mangle] +static mut __pfnDliNotifyHook2: *mut PfnDliHook = load_exe_hook as *mut PfnDliHook;