From 929c3e50fafecc920891d9b94a8913c5c175f88b Mon Sep 17 00:00:00 2001 From: Christopher Vella Date: Mon, 26 May 2025 13:30:21 +1000 Subject: [PATCH 1/5] Allow pinning of windows modules --- src/os/windows/mod.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 1cbc57be3..deacabf43 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -171,6 +171,36 @@ impl Library { ret } + /// Attempts to pin the module represented by the current `Library` into memory. + /// If successful, the module will remain in memory regardless of the refcount for this `Library` + pub fn pin(&self) -> Result<(), crate::Error> { + const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 0x1; + const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x4; + let ret = unsafe { + let mut handle: HMODULE = 0; + with_get_last_error( + |source| crate::Error::GetModuleHandleExW { source }, + || { + // Make sure no winapi calls as a result of drop happen inside this closure, because + // otherwise that might change the return value of the GetLastError. + let result = GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + self.0 as *const u16, + &mut handle, + ); + if result == 0 { + None + } else { + Some(()) + } + }, + ) + .map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown)) + }; + + ret + } + /// Get a pointer to a function or static variable by symbol name. /// /// The `symbol` may not contain any null bytes, with the exception of the last byte. A null From d83bc9e35e02496e5d64d5b67555de2e080e0fb1 Mon Sep 17 00:00:00 2001 From: Christopher Vella Date: Mon, 26 May 2025 13:39:47 +1000 Subject: [PATCH 2/5] Add test for module pinning on windows --- tests/functions.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/functions.rs b/tests/functions.rs index c94592e7a..84d5267d9 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -279,6 +279,17 @@ fn works_getlasterror0() { } } +#[cfg(windows)] +#[test] +fn works_pin_module() { + use libloading::os::windows::Library; + + unsafe { + let lib = Library::new("kernel32.dll").unwrap(); + lib.pin().unwrap(); + } +} + #[cfg(windows)] #[test] fn library_open_already_loaded() { From 3e2d21d36f70ea87dbe9b8df0a1b44f5305d9229 Mon Sep 17 00:00:00 2001 From: Christopher Vella Date: Mon, 26 May 2025 13:44:27 +1000 Subject: [PATCH 3/5] Comment update --- src/os/windows/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index deacabf43..f13b611dd 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -183,6 +183,10 @@ impl Library { || { // Make sure no winapi calls as a result of drop happen inside this closure, because // otherwise that might change the return value of the GetLastError. + + // We use our cached module handle of this `Library` instead of the module name. This works + // if we also pass the flag `GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS` because on Windows, module handles + // are the loaded base address of the module. let result = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, self.0 as *const u16, From 24c9d70f47ef05aa800b1e919bc76565a0d74582 Mon Sep 17 00:00:00 2001 From: Christopher Vella Date: Tue, 27 May 2025 07:46:05 +1000 Subject: [PATCH 4/5] Comment update --- src/os/windows/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index f13b611dd..07ee5c846 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -172,6 +172,12 @@ impl Library { } /// Attempts to pin the module represented by the current `Library` into memory. + /// + /// Calls `GetModuleHandleExW` with the flag `GET_MODULE_HANDLE_EX_FLAG_PIN` to pin the module. + /// See the [MSDN documentation][msdn] for more information. + /// + /// [msdn]: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw + /// /// If successful, the module will remain in memory regardless of the refcount for this `Library` pub fn pin(&self) -> Result<(), crate::Error> { const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 0x1; From 7585067cf62999ebe0dd724dcb7e09b067a6a937 Mon Sep 17 00:00:00 2001 From: Christopher Vella Date: Tue, 27 May 2025 08:00:50 +1000 Subject: [PATCH 5/5] cargo clippy --- src/os/windows/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 07ee5c846..59fa69a5e 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -182,7 +182,7 @@ impl Library { pub fn pin(&self) -> Result<(), crate::Error> { const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 0x1; const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x4; - let ret = unsafe { + unsafe { let mut handle: HMODULE = 0; with_get_last_error( |source| crate::Error::GetModuleHandleExW { source }, @@ -206,9 +206,7 @@ impl Library { }, ) .map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown)) - }; - - ret + } } /// Get a pointer to a function or static variable by symbol name.