Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows: drop dependency on windows-sys #125

Merged
merged 2 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/libloading.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust_toolchain: [nightly, stable, 1.48.0]
rust_toolchain: [nightly, stable, 1.56.0]
os: [ubuntu-latest, windows-latest, macOS-latest]
timeout-minutes: 20
steps:
Expand Down
14 changes: 5 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "libloading"
# When bumping
# * Don’t forget to add an entry to `src/changelog.rs`
# * If bumping to an incompatible version, adjust the documentation in `src/lib.rs`
version = "0.8.1"
version = "0.8.2"
authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
license = "ISC"
repository = "https://github.com/nagisa/rust_libloading/"
Expand All @@ -12,22 +12,18 @@ readme = "README.mkd"
description = "Bindings around the platform's dynamic library loading primitives with greatly improved memory safety."
keywords = ["dlopen", "load", "shared", "dylib"]
categories = ["api-bindings"]
rust-version = "1.48.0"
rust-version = "1.56.0"

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.52"
features = [
"Win32_Foundation",
"Win32_System_Diagnostics_Debug",
"Win32_System_LibraryLoader",
]
[target.'cfg(windows)'.dependencies.windows-targets]
version = ">=0.48, <0.53"

[target.'cfg(unix)'.dependencies.cfg-if]
version = "1"

[dev-dependencies]
libc = "0.2"
static_assertions = "1.1"
windows-sys = { version = "0.52", features = ["Win32_Foundation"] }

[package.metadata.docs.rs]
all-features = true
Expand Down
17 changes: 17 additions & 0 deletions src/changelog.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
//! The change log.

/// Release 0.8.2 (2024-03-01)
///
/// ## (Potentially) breaking changes
///
/// MSRV has been increased to 1.56.0. Since both rustc versions are ancient, this has been deemed
/// to not be breaking enough to warrant a semver-breaking release of libloading. If you're stick
/// with a version of rustc older than 1.56.0, lock `libloading` dependency to `0.8.1`.
///
/// ## Non-breaking changes
///
/// The crate switches the dependency on `windows-sys` to a `windows-target` one for Windows
/// bindings. In order to enable this `libloading` defines any bindings necessary for its operation
/// internally, just like has been done for `unix` targets. This should result in leaner
/// dependency trees.
pub mod r0_8_2 {}

/// Release 0.8.1 (2023-09-30)
///
/// ## Non-breaking changes
///
/// * Support for GNU Hurd.
pub mod r0_8_1 {}

/// Release 0.8.0 (2023-04-11)
///
Expand Down
6 changes: 2 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,13 @@
pub mod changelog;
pub mod os;
mod util;

mod error;
pub use self::error::Error;

#[cfg(any(unix, windows, libloading_docs))]
mod safe;

pub use self::error::Error;
#[cfg(any(unix, windows, libloading_docs))]
pub use self::safe::{Library, Symbol};

use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::ffi::{OsStr, OsString};

Expand Down
5 changes: 3 additions & 2 deletions src/os/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl Library {
//
// We try to leave as little space as possible for this to occur, but we can’t exactly
// fully prevent it.
match with_dlerror(|desc| crate::Error::DlSym { desc }, || {
let result = with_dlerror(|desc| crate::Error::DlSym { desc }, || {
dlerror();
let symbol = dlsym(self.handle, symbol.as_ptr());
if symbol.is_null() {
Expand All @@ -208,7 +208,8 @@ impl Library {
pd: marker::PhantomData
})
}
}) {
});
match result {
Err(None) => on_null(),
Err(Some(e)) => Err(e),
Ok(x) => Ok(x)
Expand Down
121 changes: 48 additions & 73 deletions src/os/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,18 @@
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
// same rustdoc build visible.
#[cfg(all(libloading_docs, not(windows)))]
mod windows_imports {
pub(super) enum HMODULE {}
pub(super) enum FARPROC {}
#[allow(non_camel_case_types)]
pub(super) enum THREAD_ERROR_MODE {}
#[allow(non_camel_case_types)]
pub(super) struct LOAD_LIBRARY_FLAGS;

pub(super) mod consts {
use super::LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = LOAD_LIBRARY_FLAGS;
}
}
mod windows_imports {}
#[cfg(any(not(libloading_docs), windows))]
mod windows_imports {
extern crate windows_sys;
pub(super) use self::windows_sys::Win32::Foundation::{GetLastError, FARPROC, HMODULE};
pub(super) use self::windows_sys::Win32::System::Diagnostics::Debug as debug_api;
pub(super) use self::windows_sys::Win32::System::Diagnostics::Debug::SEM_FAILCRITICALERRORS;
pub(super) use self::windows_sys::Win32::System::Diagnostics::Debug::THREAD_ERROR_MODE;

pub(super) use self::windows_sys::Win32::System::LibraryLoader as library_loader;
pub(super) use self::windows_sys::Win32::System::LibraryLoader::LOAD_LIBRARY_FLAGS;

use super::{DWORD, BOOL, HANDLE, HMODULE, FARPROC};
pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};

pub(super) mod consts {
pub(crate) use super::windows_sys::Win32::System::LibraryLoader::{
LOAD_IGNORE_CODE_AUTHZ_LEVEL,
LOAD_LIBRARY_AS_DATAFILE,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE,
LOAD_LIBRARY_AS_IMAGE_RESOURCE,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,
LOAD_LIBRARY_SEARCH_SYSTEM32,
LOAD_LIBRARY_SEARCH_USER_DIRS,
LOAD_WITH_ALTERED_SEARCH_PATH,
LOAD_LIBRARY_REQUIRE_SIGNED_TARGET,
LOAD_LIBRARY_SAFE_CURRENT_DIRS,
};
}
windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> DWORD);
windows_targets::link!("kernel32.dll" "system" fn SetThreadErrorMode(new_mode: DWORD, old_mode: *mut DWORD) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut HMODULE) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(module: HMODULE) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExW(filename: *const u16, file: HANDLE, flags: DWORD) -> HMODULE);
windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: HMODULE, filename: *mut u16, size: DWORD) -> DWORD);
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC);
}

use self::windows_imports::*;
Expand Down Expand Up @@ -124,7 +83,7 @@ impl Library {
unsafe {
let mut handle: HMODULE = 0;
with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
let result = library_loader::GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle);
let result = GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle);
if result == 0 {
None
} else {
Expand Down Expand Up @@ -159,7 +118,7 @@ impl Library {
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 = library_loader::GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle);
let result = GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle);
if result == 0 {
None
} else {
Expand Down Expand Up @@ -199,7 +158,7 @@ impl Library {
let ret = with_get_last_error(|source| crate::Error::LoadLibraryExW { 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 handle = library_loader::LoadLibraryExW(wide_filename.as_ptr(), 0, flags);
let handle = LoadLibraryExW(wide_filename.as_ptr(), 0, flags);
if handle == 0 {
None
} else {
Expand All @@ -226,7 +185,7 @@ impl Library {
ensure_compatible_types::<T, FARPROC>()?;
let symbol = cstr_cow_from_bytes(symbol)?;
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
let symbol = library_loader::GetProcAddress(self.0, symbol.as_ptr().cast());
let symbol = GetProcAddress(self.0, symbol.as_ptr().cast());
if symbol.is_none() {
None
} else {
Expand All @@ -247,7 +206,7 @@ impl Library {
ensure_compatible_types::<T, FARPROC>()?;
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
let ordinal = ordinal as usize as *const _;
let symbol = library_loader::GetProcAddress(self.0, ordinal);
let symbol = GetProcAddress(self.0, ordinal);
if symbol.is_none() {
None
} else {
Expand Down Expand Up @@ -285,7 +244,7 @@ impl Library {
/// The underlying data structures may still get leaked if an error does occur.
pub fn close(self) -> Result<(), crate::Error> {
let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || {
if unsafe { library_loader::FreeLibrary(self.0) == 0 } {
if unsafe { FreeLibrary(self.0) == 0 } {
None
} else {
Some(())
Expand All @@ -301,7 +260,7 @@ impl Library {

impl Drop for Library {
fn drop(&mut self) {
unsafe { library_loader::FreeLibrary(self.0); }
unsafe { FreeLibrary(self.0); }
}
}

Expand All @@ -311,7 +270,7 @@ impl fmt::Debug for Library {
// FIXME: use Maybeuninit::uninit_array when stable
let mut buf =
mem::MaybeUninit::<[mem::MaybeUninit<u16>; 1024]>::uninit().assume_init();
let len = library_loader::GetModuleFileNameW(self.0,
let len = GetModuleFileNameW(self.0,
buf[..].as_mut_ptr().cast(), 1024) as usize;
if len == 0 {
f.write_str(&format!("Library@{:#x}", self.0))
Expand Down Expand Up @@ -381,14 +340,14 @@ impl<T> fmt::Debug for Symbol<T> {
}
}

struct ErrorModeGuard(THREAD_ERROR_MODE);
struct ErrorModeGuard(DWORD);

impl ErrorModeGuard {
#[allow(clippy::if_same_then_else)]
fn new() -> Option<ErrorModeGuard> {
unsafe {
let mut previous_mode = 0;
if debug_api::SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
// How in the world is it possible for what is essentially a simple variable swap
// to fail? For now we just ignore the error -- the worst that can happen here is
// the previous mode staying on and user seeing a dialog error on older Windows
Expand All @@ -406,7 +365,7 @@ impl ErrorModeGuard {
impl Drop for ErrorModeGuard {
fn drop(&mut self) {
unsafe {
debug_api::SetThreadErrorMode(self.0, ptr::null_mut());
SetThreadErrorMode(self.0, ptr::null_mut());
}
}
}
Expand All @@ -424,13 +383,29 @@ where F: FnOnce() -> Option<T> {
})
}


#[allow(clippy::upper_case_acronyms)]
type BOOL = i32;
#[allow(clippy::upper_case_acronyms)]
type DWORD = u32;
#[allow(clippy::upper_case_acronyms)]
type HANDLE = isize;
#[allow(clippy::upper_case_acronyms)]
type HMODULE = isize;
#[allow(clippy::upper_case_acronyms)]
type FARPROC = Option<unsafe extern "system" fn() -> isize>;
#[allow(non_camel_case_types)]
type LOAD_LIBRARY_FLAGS = DWORD;

const SEM_FAILCRITICALERRORS: DWORD = 1;

/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
///
/// This action applies only to the DLL being loaded and not to its dependencies. This value is
/// recommended for use in setup programs that must run extracted DLLs during installation.
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL;
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010;

/// Map the file into the calling process’ virtual address space as if it were a data file.
///
Expand All @@ -440,7 +415,7 @@ pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = consts::LOAD_IGNORE
/// messages or resources from it.
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_AS_DATAFILE;
pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002;

/// Map the file into the calling process’ virtual address space as if it were a data file.
///
Expand All @@ -449,7 +424,7 @@ pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_AS
/// while it is in use. However, the DLL can still be opened by other processes.
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040;

/// Map the file into the process’ virtual address space as an image file.
///
Expand All @@ -461,15 +436,15 @@ pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = consts::LOAD_
/// [`LOAD_LIBRARY_AS_DATAFILE`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020;

/// Search the application's installation directory for the DLL and its dependencies.
///
/// Directories in the standard search path are not searched. This value cannot be combined with
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200;

/// Search default directories when looking for the DLL and its dependencies.
///
Expand All @@ -479,7 +454,7 @@ pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = consts::LOAD
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000;

/// Directory that contains the DLL is temporarily added to the beginning of the list of
/// directories that are searched for the DLL’s dependencies.
Expand All @@ -490,15 +465,15 @@ pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = consts::LOAD_LI
/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100;

/// Search `%windows%\system32` for the DLL and its dependencies.
///
/// Directories in the standard search path are not searched. This value cannot be combined with
/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SEARCH_SYSTEM32;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800;

/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
/// for the DLL and its dependencies.
Expand All @@ -508,7 +483,7 @@ pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRAR
/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400;

/// If `filename` specifies an absolute path, the system uses the alternate file search strategy
/// discussed in the [Remarks section] to find associated executable modules that the specified
Expand All @@ -523,15 +498,15 @@ pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRA
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
///
/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = consts::LOAD_WITH_ALTERED_SEARCH_PATH;
pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008;

/// Specifies that the digital signature of the binary image must be checked at load time.
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080;

/// Allow loading a DLL for execution from the current directory only if it is under a directory in
/// the Safe load list.
///
/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000;
Loading