libloading/os/windows/mod.rs
1// A hack for docs.rs to build documentation that has both windows and linux documentation in the
2// same rustdoc build visible.
3#[cfg(all(libloading_docs, not(windows)))]
4mod windows_imports {}
5#[cfg(any(not(libloading_docs), windows))]
6mod windows_imports {
7 use super::{DWORD, BOOL, HANDLE, HMODULE, FARPROC};
8 pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt};
9 windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> DWORD);
10 windows_targets::link!("kernel32.dll" "system" fn SetThreadErrorMode(new_mode: DWORD, old_mode: *mut DWORD) -> BOOL);
11 windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleExW(flags: u32, module_name: *const u16, module: *mut HMODULE) -> BOOL);
12 windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(module: HMODULE) -> BOOL);
13 windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExW(filename: *const u16, file: HANDLE, flags: DWORD) -> HMODULE);
14 windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(module: HMODULE, filename: *mut u16, size: DWORD) -> DWORD);
15 windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC);
16}
17
18use self::windows_imports::*;
19use util::{ensure_compatible_types, cstr_cow_from_bytes};
20use std::ffi::{OsStr, OsString};
21use std::{fmt, io, marker, mem, ptr};
22use std::os::raw;
23
24/// The platform-specific counterpart of the cross-platform [`Library`](crate::Library).
25pub struct Library(HMODULE);
26
27unsafe impl Send for Library {}
28// Now, this is sort-of-tricky. MSDN documentation does not really make any claims as to safety of
29// the Win32 APIs. Sadly, whomever I asked, even current and former Microsoft employees, couldn’t
30// say for sure whether the Win32 APIs used to implement `Library` are thread-safe or not.
31//
32// My investigation ended up with a question about thread-safety properties of the API involved
33// being sent to an internal (to MS) general question mailing-list. The conclusion of the mail is
34// as such:
35//
36// * Nobody inside MS (at least out of all of the people who have seen the question) knows for
37// sure either;
38// * However, the general consensus between MS developers is that one can rely on the API being
39// thread-safe. In case it is not thread-safe it should be considered a bug on the Windows
40// part. (NB: bugs filed at https://connect.microsoft.com/ against Windows Server)
41unsafe impl Sync for Library {}
42
43impl Library {
44 /// Find and load a module.
45 ///
46 /// If the `filename` specifies a full path, the function only searches that path for the
47 /// module. Otherwise, if the `filename` specifies a relative path or a module name without a
48 /// path, the function uses a Windows-specific search strategy to find the module. For more
49 /// information, see the [Remarks on MSDN][msdn].
50 ///
51 /// If the `filename` specifies a library filename without a path and with the extension omitted,
52 /// the `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
53 /// trailing `.` to the `filename`.
54 ///
55 /// This is equivalent to <code>[Library::load_with_flags](filename, 0)</code>.
56 ///
57 /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks
58 ///
59 /// # Safety
60 ///
61 /// When a library is loaded, initialisation routines contained within the library are executed.
62 /// For the purposes of safety, the execution of these routines is conceptually the same calling an
63 /// unknown foreign function and may impose arbitrary requirements on the caller for the call
64 /// to be sound.
65 ///
66 /// Additionally, the callers of this function must also ensure that execution of the
67 /// termination routines contained within the library is safe as well. These routines may be
68 /// executed when the library is unloaded.
69 #[inline]
70 pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
71 Library::load_with_flags(filename, 0)
72 }
73
74 /// Get the `Library` representing the original program executable.
75 ///
76 /// Note that the behaviour of the `Library` loaded with this method is different from
77 /// Libraries loaded with [`os::unix::Library::this`]. For more information refer to [MSDN].
78 ///
79 /// Corresponds to `GetModuleHandleExW(0, NULL, _)`.
80 ///
81 /// [`os::unix::Library::this`]: crate::os::unix::Library::this
82 /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
83 pub fn this() -> Result<Library, crate::Error> {
84 unsafe {
85 let mut handle: HMODULE = 0;
86 with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
87 let result = GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle);
88 if result == 0 {
89 None
90 } else {
91 Some(Library(handle))
92 }
93 }).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
94 }
95 }
96
97 /// Get a module that is already loaded by the program.
98 ///
99 /// This function returns a `Library` corresponding to a module with the given name that is
100 /// already mapped into the address space of the process. If the module isn't found, an error is
101 /// returned.
102 ///
103 /// If the `filename` does not include a full path and there are multiple different loaded
104 /// modules corresponding to the `filename`, it is impossible to predict which module handle
105 /// will be returned. For more information refer to [MSDN].
106 ///
107 /// If the `filename` specifies a library filename without a path and with the extension omitted,
108 /// the `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
109 /// trailing `.` to the `filename`.
110 ///
111 /// This is equivalent to `GetModuleHandleExW(0, filename, _)`.
112 ///
113 /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
114 pub fn open_already_loaded<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error> {
115 let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
116
117 let ret = unsafe {
118 let mut handle: HMODULE = 0;
119 with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || {
120 // Make sure no winapi calls as a result of drop happen inside this closure, because
121 // otherwise that might change the return value of the GetLastError.
122 let result = GetModuleHandleExW(0, wide_filename.as_ptr(), &mut handle);
123 if result == 0 {
124 None
125 } else {
126 Some(Library(handle))
127 }
128 }).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
129 };
130
131 drop(wide_filename); // Drop wide_filename here to ensure it doesn’t get moved and dropped
132 // inside the closure by mistake. See comment inside the closure.
133 ret
134 }
135
136 /// Find and load a module, additionally adjusting behaviour with flags.
137 ///
138 /// See [`Library::new`] for documentation on the handling of the `filename` argument. See the
139 /// [flag table on MSDN][flags] for information on applicable values for the `flags` argument.
140 ///
141 /// Corresponds to `LoadLibraryExW(filename, reserved: NULL, flags)`.
142 ///
143 /// [flags]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters
144 ///
145 /// # Safety
146 ///
147 /// When a library is loaded, initialisation routines contained within the library are executed.
148 /// For the purposes of safety, the execution of these routines is conceptually the same calling an
149 /// unknown foreign function and may impose arbitrary requirements on the caller for the call
150 /// to be sound.
151 ///
152 /// Additionally, the callers of this function must also ensure that execution of the
153 /// termination routines contained within the library is safe as well. These routines may be
154 /// executed when the library is unloaded.
155 pub unsafe fn load_with_flags<P: AsRef<OsStr>>(filename: P, flags: LOAD_LIBRARY_FLAGS) -> Result<Library, crate::Error> {
156 let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
157 let _guard = ErrorModeGuard::new();
158
159 let ret = with_get_last_error(|source| crate::Error::LoadLibraryExW { source }, || {
160 // Make sure no winapi calls as a result of drop happen inside this closure, because
161 // otherwise that might change the return value of the GetLastError.
162 let handle = LoadLibraryExW(wide_filename.as_ptr(), 0, flags);
163 if handle == 0 {
164 None
165 } else {
166 Some(Library(handle))
167 }
168 }).map_err(|e| e.unwrap_or(crate::Error::LoadLibraryExWUnknown));
169 drop(wide_filename); // Drop wide_filename here to ensure it doesn’t get moved and dropped
170 // inside the closure by mistake. See comment inside the closure.
171 ret
172 }
173
174 /// Attempts to pin the module represented by the current `Library` into memory.
175 ///
176 /// Calls `GetModuleHandleExW` with the flag `GET_MODULE_HANDLE_EX_FLAG_PIN` to pin the module.
177 /// See the [MSDN documentation][msdn] for more information.
178 ///
179 /// [msdn]: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw
180 ///
181 /// If successful, the module will remain in memory regardless of the refcount for this `Library`
182 pub fn pin(&self) -> Result<(), crate::Error> {
183 const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 0x1;
184 const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x4;
185 unsafe {
186 let mut handle: HMODULE = 0;
187 with_get_last_error(
188 |source| crate::Error::GetModuleHandleExW { source },
189 || {
190 // Make sure no winapi calls as a result of drop happen inside this closure, because
191 // otherwise that might change the return value of the GetLastError.
192
193 // We use our cached module handle of this `Library` instead of the module name. This works
194 // if we also pass the flag `GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS` because on Windows, module handles
195 // are the loaded base address of the module.
196 let result = GetModuleHandleExW(
197 GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
198 self.0 as *const u16,
199 &mut handle,
200 );
201 if result == 0 {
202 None
203 } else {
204 Some(())
205 }
206 },
207 )
208 .map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown))
209 }
210 }
211
212 /// Get a pointer to a function or static variable by symbol name.
213 ///
214 /// The `symbol` may not contain any null bytes, with the exception of the last byte. A null
215 /// terminated `symbol` may avoid a string allocation in some cases.
216 ///
217 /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
218 /// most likely invalid.
219 ///
220 /// # Safety
221 ///
222 /// Users of this API must specify the correct type of the function or variable loaded.
223 pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
224 ensure_compatible_types::<T, FARPROC>()?;
225 let symbol = cstr_cow_from_bytes(symbol)?;
226 with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
227 let symbol = GetProcAddress(self.0, symbol.as_ptr().cast());
228 if symbol.is_none() {
229 None
230 } else {
231 Some(Symbol {
232 pointer: symbol,
233 pd: marker::PhantomData
234 })
235 }
236 }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
237 }
238
239 /// Get a pointer to a function or static variable by ordinal number.
240 ///
241 /// # Safety
242 ///
243 /// Users of this API must specify the correct type of the function or variable loaded.
244 pub unsafe fn get_ordinal<T>(&self, ordinal: u16) -> Result<Symbol<T>, crate::Error> {
245 ensure_compatible_types::<T, FARPROC>()?;
246 with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
247 let ordinal = ordinal as usize as *const _;
248 let symbol = GetProcAddress(self.0, ordinal);
249 if symbol.is_none() {
250 None
251 } else {
252 Some(Symbol {
253 pointer: symbol,
254 pd: marker::PhantomData
255 })
256 }
257 }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
258 }
259
260 /// Convert the `Library` to a raw handle.
261 pub fn into_raw(self) -> HMODULE {
262 let handle = self.0;
263 mem::forget(self);
264 handle
265 }
266
267 /// Convert a raw handle to a `Library`.
268 ///
269 /// # Safety
270 ///
271 /// The handle must be the result of a successful call of `LoadLibraryA`, `LoadLibraryW`,
272 /// `LoadLibraryExW`, or `LoadLibraryExA`, or a handle previously returned by the
273 /// `Library::into_raw` call.
274 pub unsafe fn from_raw(handle: HMODULE) -> Library {
275 Library(handle)
276 }
277
278 /// Unload the library.
279 ///
280 /// You only need to call this if you are interested in handling any errors that may arise when
281 /// library is unloaded. Otherwise this will be done when `Library` is dropped.
282 ///
283 /// The underlying data structures may still get leaked if an error does occur.
284 pub fn close(self) -> Result<(), crate::Error> {
285 let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || {
286 if unsafe { FreeLibrary(self.0) == 0 } {
287 None
288 } else {
289 Some(())
290 }
291 }).map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
292 // While the library is not free'd yet in case of an error, there is no reason to try
293 // dropping it again, because all that will do is try calling `FreeLibrary` again. only
294 // this time it would ignore the return result, which we already seen failing...
295 std::mem::forget(self);
296 result
297 }
298}
299
300impl Drop for Library {
301 fn drop(&mut self) {
302 unsafe { FreeLibrary(self.0); }
303 }
304}
305
306impl fmt::Debug for Library {
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 unsafe {
309 // FIXME: use Maybeuninit::uninit_array when stable
310 let mut buf =
311 mem::MaybeUninit::<[mem::MaybeUninit<u16>; 1024]>::uninit().assume_init();
312 let len = GetModuleFileNameW(self.0,
313 buf[..].as_mut_ptr().cast(), 1024) as usize;
314 if len == 0 {
315 f.write_str(&format!("Library@{:#x}", self.0))
316 } else {
317 let string: OsString = OsString::from_wide(
318 // FIXME: use Maybeuninit::slice_get_ref when stable
319 &*(&buf[..len] as *const [_] as *const [u16]),
320 );
321 f.write_str(&format!("Library@{:#x} from {:?}", self.0, string))
322 }
323 }
324 }
325}
326
327/// A symbol from a library.
328///
329/// A major difference compared to the cross-platform `Symbol` is that this does not ensure that the
330/// `Symbol` does not outlive the `Library` that it comes from.
331pub struct Symbol<T> {
332 pointer: FARPROC,
333 pd: marker::PhantomData<T>
334}
335
336impl<T> Symbol<T> {
337 /// Convert the loaded `Symbol` into a handle.
338 pub fn into_raw(self) -> FARPROC {
339 self.pointer
340 }
341
342 /// Convert the loaded `Symbol` into a raw pointer.
343 pub fn as_raw_ptr(self) -> *mut raw::c_void {
344 self.pointer
345 .map(|raw| raw as *mut raw::c_void)
346 .unwrap_or(std::ptr::null_mut())
347 }
348}
349
350impl<T> Symbol<Option<T>> {
351 /// Lift Option out of the symbol.
352 pub fn lift_option(self) -> Option<Symbol<T>> {
353 if self.pointer.is_none() {
354 None
355 } else {
356 Some(Symbol {
357 pointer: self.pointer,
358 pd: marker::PhantomData,
359 })
360 }
361 }
362}
363
364unsafe impl<T: Send> Send for Symbol<T> {}
365unsafe impl<T: Sync> Sync for Symbol<T> {}
366
367impl<T> Clone for Symbol<T> {
368 fn clone(&self) -> Symbol<T> {
369 Symbol { ..*self }
370 }
371}
372
373impl<T> ::std::ops::Deref for Symbol<T> {
374 type Target = T;
375 fn deref(&self) -> &T {
376 unsafe { &*((&self.pointer) as *const FARPROC as *const T) }
377 }
378}
379
380impl<T> fmt::Debug for Symbol<T> {
381 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382 match self.pointer {
383 None => f.write_str("Symbol@0x0"),
384 Some(ptr) => f.write_str(&format!("Symbol@{:p}", ptr as *const ())),
385 }
386 }
387}
388
389struct ErrorModeGuard(DWORD);
390
391impl ErrorModeGuard {
392 #[allow(clippy::if_same_then_else)]
393 fn new() -> Option<ErrorModeGuard> {
394 unsafe {
395 let mut previous_mode = 0;
396 if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
397 // How in the world is it possible for what is essentially a simple variable swap
398 // to fail? For now we just ignore the error -- the worst that can happen here is
399 // the previous mode staying on and user seeing a dialog error on older Windows
400 // machines.
401 None
402 } else if previous_mode == SEM_FAILCRITICALERRORS {
403 None
404 } else {
405 Some(ErrorModeGuard(previous_mode))
406 }
407 }
408 }
409}
410
411impl Drop for ErrorModeGuard {
412 fn drop(&mut self) {
413 unsafe {
414 SetThreadErrorMode(self.0, ptr::null_mut());
415 }
416 }
417}
418
419fn with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F)
420-> Result<T, Option<crate::Error>>
421where F: FnOnce() -> Option<T> {
422 closure().ok_or_else(|| {
423 let error = unsafe { GetLastError() };
424 if error == 0 {
425 None
426 } else {
427 Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
428 }
429 })
430}
431
432
433#[allow(clippy::upper_case_acronyms)]
434type BOOL = i32;
435#[allow(clippy::upper_case_acronyms)]
436type DWORD = u32;
437#[allow(clippy::upper_case_acronyms)]
438type HANDLE = isize;
439#[allow(clippy::upper_case_acronyms)]
440type HMODULE = isize;
441#[allow(clippy::upper_case_acronyms)]
442type FARPROC = Option<unsafe extern "system" fn() -> isize>;
443#[allow(non_camel_case_types)]
444type LOAD_LIBRARY_FLAGS = DWORD;
445
446const SEM_FAILCRITICALERRORS: DWORD = 1;
447
448/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
449///
450/// This action applies only to the DLL being loaded and not to its dependencies. This value is
451/// recommended for use in setup programs that must run extracted DLLs during installation.
452///
453/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
454pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010;
455
456/// Map the file into the calling process’ virtual address space as if it were a data file.
457///
458/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call
459/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only
460/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract
461/// messages or resources from it.
462///
463/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
464pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002;
465
466/// Map the file into the calling process’ virtual address space as if it were a data file.
467///
468/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive
469/// write access for the calling process. Other processes cannot open the DLL file for write access
470/// while it is in use. However, the DLL can still be opened by other processes.
471///
472/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
473pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040;
474
475/// Map the file into the process’ virtual address space as an image file.
476///
477/// The loader does not load the static imports or perform the other usual initialisation steps.
478/// Use this flag when you want to load a DLL only to extract messages or resources from it.
479///
480/// Unless the application depends on the file having the in-memory layout of an image, this value
481/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or
482/// [`LOAD_LIBRARY_AS_DATAFILE`].
483///
484/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
485pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020;
486
487/// Search the application's installation directory for the DLL and its dependencies.
488///
489/// Directories in the standard search path are not searched. This value cannot be combined with
490/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
491///
492/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
493pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200;
494
495/// Search default directories when looking for the DLL and its dependencies.
496///
497/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`],
498/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the
499/// standard search path are not searched. This value cannot be combined with
500/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
501///
502/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
503pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000;
504
505/// Directory that contains the DLL is temporarily added to the beginning of the list of
506/// directories that are searched for the DLL’s dependencies.
507///
508/// Directories in the standard search path are not searched.
509///
510/// The `filename` parameter must specify a fully qualified path. This value cannot be combined
511/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
512///
513/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
514pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100;
515
516/// Search `%windows%\system32` for the DLL and its dependencies.
517///
518/// Directories in the standard search path are not searched. This value cannot be combined with
519/// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
520///
521/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
522pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800;
523
524/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
525/// for the DLL and its dependencies.
526///
527/// If more than one directory has been added, the order in which the directories are searched is
528/// unspecified. Directories in the standard search path are not searched. This value cannot be
529/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
530///
531/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
532pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400;
533
534/// If `filename` specifies an absolute path, the system uses the alternate file search strategy
535/// discussed in the [Remarks section] to find associated executable modules that the specified
536/// module causes to be loaded.
537///
538/// If this value is used and `filename` specifies a relative path, the behaviour is undefined.
539///
540/// If this value is not used, or if `filename` does not specify a path, the system uses the
541/// standard search strategy discussed in the [Remarks section] to find associated executable
542/// modules that the specified module causes to be loaded.
543///
544/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
545///
546/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
547pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008;
548
549/// Specifies that the digital signature of the binary image must be checked at load time.
550///
551/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
552pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080;
553
554/// Allow loading a DLL for execution from the current directory only if it is under a directory in
555/// the Safe load list.
556///
557/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
558pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000;