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