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;