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