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;