• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)))]
4 mod windows_imports {}
5 #[cfg(any(not(libloading_docs), windows))]
6 mod 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 
18 use self::windows_imports::*;
19 use util::{ensure_compatible_types, cstr_cow_from_bytes};
20 use std::ffi::{OsStr, OsString};
21 use std::{fmt, io, marker, mem, ptr};
22 use std::os::raw;
23 
24 /// The platform-specific counterpart of the cross-platform [`Library`](crate::Library).
25 pub struct Library(HMODULE);
26 
27 unsafe 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)
41 unsafe impl Sync for Library {}
42 
43 impl 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]
new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error>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
this() -> Result<Library, crate::Error>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
open_already_loaded<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error>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.
load_with_flags<P: AsRef<OsStr>>(filename: P, flags: LOAD_LIBRARY_FLAGS) -> Result<Library, crate::Error>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     /// Get a pointer to a function or static variable by symbol name.
175     ///
176     /// The `symbol` may not contain any null bytes, with the exception of the last byte. A null
177     /// terminated `symbol` may avoid a string allocation in some cases.
178     ///
179     /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
180     /// most likely invalid.
181     ///
182     /// # Safety
183     ///
184     /// Users of this API must specify the correct type of the function or variable loaded.
get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error>185     pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
186         ensure_compatible_types::<T, FARPROC>()?;
187         let symbol = cstr_cow_from_bytes(symbol)?;
188         with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
189             let symbol = GetProcAddress(self.0, symbol.as_ptr().cast());
190             if symbol.is_none() {
191                 None
192             } else {
193                 Some(Symbol {
194                     pointer: symbol,
195                     pd: marker::PhantomData
196                 })
197             }
198         }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
199     }
200 
201     /// Get a pointer to a function or static variable by ordinal number.
202     ///
203     /// # Safety
204     ///
205     /// Users of this API must specify the correct type of the function or variable loaded.
get_ordinal<T>(&self, ordinal: u16) -> Result<Symbol<T>, crate::Error>206     pub unsafe fn get_ordinal<T>(&self, ordinal: u16) -> Result<Symbol<T>, crate::Error> {
207         ensure_compatible_types::<T, FARPROC>()?;
208         with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
209             let ordinal = ordinal as usize as *const _;
210             let symbol = GetProcAddress(self.0, ordinal);
211             if symbol.is_none() {
212                 None
213             } else {
214                 Some(Symbol {
215                     pointer: symbol,
216                     pd: marker::PhantomData
217                 })
218             }
219         }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
220     }
221 
222     /// Convert the `Library` to a raw handle.
into_raw(self) -> HMODULE223     pub fn into_raw(self) -> HMODULE {
224         let handle = self.0;
225         mem::forget(self);
226         handle
227     }
228 
229     /// Convert a raw handle to a `Library`.
230     ///
231     /// # Safety
232     ///
233     /// The handle must be the result of a successful call of `LoadLibraryA`, `LoadLibraryW`,
234     /// `LoadLibraryExW`, or `LoadLibraryExA`, or a handle previously returned by the
235     /// `Library::into_raw` call.
from_raw(handle: HMODULE) -> Library236     pub unsafe fn from_raw(handle: HMODULE) -> Library {
237         Library(handle)
238     }
239 
240     /// Unload the library.
241     ///
242     /// You only need to call this if you are interested in handling any errors that may arise when
243     /// library is unloaded. Otherwise this will be done when `Library` is dropped.
244     ///
245     /// The underlying data structures may still get leaked if an error does occur.
close(self) -> Result<(), crate::Error>246     pub fn close(self) -> Result<(), crate::Error> {
247         let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || {
248             if unsafe { FreeLibrary(self.0) == 0 } {
249                 None
250             } else {
251                 Some(())
252             }
253         }).map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
254         // While the library is not free'd yet in case of an error, there is no reason to try
255         // dropping it again, because all that will do is try calling `FreeLibrary` again. only
256         // this time it would ignore the return result, which we already seen failing...
257         std::mem::forget(self);
258         result
259     }
260 }
261 
262 impl Drop for Library {
drop(&mut self)263     fn drop(&mut self) {
264         unsafe { FreeLibrary(self.0); }
265     }
266 }
267 
268 impl fmt::Debug for Library {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result269     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270         unsafe {
271             // FIXME: use Maybeuninit::uninit_array when stable
272             let mut buf =
273                 mem::MaybeUninit::<[mem::MaybeUninit<u16>; 1024]>::uninit().assume_init();
274             let len = GetModuleFileNameW(self.0,
275                 buf[..].as_mut_ptr().cast(), 1024) as usize;
276             if len == 0 {
277                 f.write_str(&format!("Library@{:#x}", self.0))
278             } else {
279                 let string: OsString = OsString::from_wide(
280                     // FIXME: use Maybeuninit::slice_get_ref when stable
281                     &*(&buf[..len] as *const [_] as *const [u16]),
282                 );
283                 f.write_str(&format!("Library@{:#x} from {:?}", self.0, string))
284             }
285         }
286     }
287 }
288 
289 /// A symbol from a library.
290 ///
291 /// A major difference compared to the cross-platform `Symbol` is that this does not ensure that the
292 /// `Symbol` does not outlive the `Library` that it comes from.
293 pub struct Symbol<T> {
294     pointer: FARPROC,
295     pd: marker::PhantomData<T>
296 }
297 
298 impl<T> Symbol<T> {
299     /// Convert the loaded `Symbol` into a handle.
into_raw(self) -> FARPROC300     pub fn into_raw(self) -> FARPROC {
301         self.pointer
302     }
303 
304     /// Convert the loaded `Symbol` into a raw pointer.
as_raw_ptr(self) -> *mut raw::c_void305     pub fn as_raw_ptr(self) -> *mut raw::c_void {
306         self.pointer
307             .map(|raw| raw as *mut raw::c_void)
308             .unwrap_or(std::ptr::null_mut())
309     }
310 }
311 
312 impl<T> Symbol<Option<T>> {
313     /// Lift Option out of the symbol.
lift_option(self) -> Option<Symbol<T>>314     pub fn lift_option(self) -> Option<Symbol<T>> {
315         if self.pointer.is_none() {
316             None
317         } else {
318             Some(Symbol {
319                 pointer: self.pointer,
320                 pd: marker::PhantomData,
321             })
322         }
323     }
324 }
325 
326 unsafe impl<T: Send> Send for Symbol<T> {}
327 unsafe impl<T: Sync> Sync for Symbol<T> {}
328 
329 impl<T> Clone for Symbol<T> {
clone(&self) -> Symbol<T>330     fn clone(&self) -> Symbol<T> {
331         Symbol { ..*self }
332     }
333 }
334 
335 impl<T> ::std::ops::Deref for Symbol<T> {
336     type Target = T;
deref(&self) -> &T337     fn deref(&self) -> &T {
338         unsafe { &*((&self.pointer) as *const FARPROC as *const T) }
339     }
340 }
341 
342 impl<T> fmt::Debug for Symbol<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result343     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344         match self.pointer {
345             None => f.write_str("Symbol@0x0"),
346             Some(ptr) => f.write_str(&format!("Symbol@{:p}", ptr as *const ())),
347         }
348     }
349 }
350 
351 struct ErrorModeGuard(DWORD);
352 
353 impl ErrorModeGuard {
354     #[allow(clippy::if_same_then_else)]
new() -> Option<ErrorModeGuard>355     fn new() -> Option<ErrorModeGuard> {
356         unsafe {
357             let mut previous_mode = 0;
358             if SetThreadErrorMode(SEM_FAILCRITICALERRORS, &mut previous_mode) == 0 {
359                 // How in the world is it possible for what is essentially a simple variable swap
360                 // to fail?  For now we just ignore the error -- the worst that can happen here is
361                 // the previous mode staying on and user seeing a dialog error on older Windows
362                 // machines.
363                 None
364             } else if previous_mode == SEM_FAILCRITICALERRORS {
365                 None
366             } else {
367                 Some(ErrorModeGuard(previous_mode))
368             }
369         }
370     }
371 }
372 
373 impl Drop for ErrorModeGuard {
drop(&mut self)374     fn drop(&mut self) {
375         unsafe {
376             SetThreadErrorMode(self.0, ptr::null_mut());
377         }
378     }
379 }
380 
with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F) -> Result<T, Option<crate::Error>> where F: FnOnce() -> Option<T>381 fn with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F)
382 -> Result<T, Option<crate::Error>>
383 where F: FnOnce() -> Option<T> {
384     closure().ok_or_else(|| {
385         let error = unsafe { GetLastError() };
386         if error == 0 {
387             None
388         } else {
389             Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
390         }
391     })
392 }
393 
394 
395 #[allow(clippy::upper_case_acronyms)]
396 type BOOL = i32;
397 #[allow(clippy::upper_case_acronyms)]
398 type DWORD = u32;
399 #[allow(clippy::upper_case_acronyms)]
400 type HANDLE = isize;
401 #[allow(clippy::upper_case_acronyms)]
402 type HMODULE = isize;
403 #[allow(clippy::upper_case_acronyms)]
404 type FARPROC = Option<unsafe extern "system" fn() -> isize>;
405 #[allow(non_camel_case_types)]
406 type LOAD_LIBRARY_FLAGS = DWORD;
407 
408 const SEM_FAILCRITICALERRORS: DWORD = 1;
409 
410 /// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
411 ///
412 /// This action applies only to the DLL being loaded and not to its dependencies. This value is
413 /// recommended for use in setup programs that must run extracted DLLs during installation.
414 ///
415 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
416 pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: LOAD_LIBRARY_FLAGS = 0x00000010;
417 
418 /// Map the file into the calling process’ virtual address space as if it were a data file.
419 ///
420 /// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call
421 /// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only
422 /// memory to raise an access violation. Use this flag when you want to load a DLL only to extract
423 /// messages or resources from it.
424 ///
425 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
426 pub const LOAD_LIBRARY_AS_DATAFILE: LOAD_LIBRARY_FLAGS = 0x00000002;
427 
428 /// Map the file into the calling process’ virtual address space as if it were a data file.
429 ///
430 /// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive
431 /// write access for the calling process. Other processes cannot open the DLL file for write access
432 /// while it is in use. However, the DLL can still be opened by other processes.
433 ///
434 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
435 pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: LOAD_LIBRARY_FLAGS = 0x00000040;
436 
437 /// Map the file into the process’ virtual address space as an image file.
438 ///
439 /// The loader does not load the static imports or perform the other usual initialisation steps.
440 /// Use this flag when you want to load a DLL only to extract messages or resources from it.
441 ///
442 /// Unless the application depends on the file having the in-memory layout of an image, this value
443 /// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or
444 /// [`LOAD_LIBRARY_AS_DATAFILE`].
445 ///
446 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
447 pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: LOAD_LIBRARY_FLAGS = 0x00000020;
448 
449 /// Search the application's installation directory for the DLL and its dependencies.
450 ///
451 /// Directories in the standard search path are not searched. This value cannot be combined with
452 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
453 ///
454 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
455 pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: LOAD_LIBRARY_FLAGS = 0x00000200;
456 
457 /// Search default directories when looking for the DLL and its dependencies.
458 ///
459 /// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`],
460 /// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the
461 /// standard search path are not searched. This value cannot be combined with
462 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
463 ///
464 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
465 pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 0x00001000;
466 
467 /// Directory that contains the DLL is temporarily added to the beginning of the list of
468 /// directories that are searched for the DLL’s dependencies.
469 ///
470 /// Directories in the standard search path are not searched.
471 ///
472 /// The `filename` parameter must specify a fully qualified path. This value cannot be combined
473 /// with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
474 ///
475 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
476 pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: LOAD_LIBRARY_FLAGS = 0x00000100;
477 
478 /// Search `%windows%\system32` for the DLL and its dependencies.
479 ///
480 /// Directories in the standard search path are not searched. This value cannot be combined with
481 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
482 ///
483 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
484 pub const LOAD_LIBRARY_SEARCH_SYSTEM32: LOAD_LIBRARY_FLAGS = 0x00000800;
485 
486 ///  Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
487 ///  for the DLL and its dependencies.
488 ///
489 ///  If more than one directory has been added, the order in which the directories are searched is
490 ///  unspecified. Directories in the standard search path are not searched. This value cannot be
491 ///  combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
492 ///
493 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
494 pub const LOAD_LIBRARY_SEARCH_USER_DIRS: LOAD_LIBRARY_FLAGS = 0x00000400;
495 
496 /// If `filename` specifies an absolute path, the system uses the alternate file search strategy
497 /// discussed in the [Remarks section] to find associated executable modules that the specified
498 /// module causes to be loaded.
499 ///
500 /// If this value is used and `filename` specifies a relative path, the behaviour is undefined.
501 ///
502 /// If this value is not used, or if `filename` does not specify a path, the system uses the
503 /// standard search strategy discussed in the [Remarks section] to find associated executable
504 /// modules that the specified module causes to be loaded.
505 ///
506 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
507 ///
508 /// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
509 pub const LOAD_WITH_ALTERED_SEARCH_PATH: LOAD_LIBRARY_FLAGS = 0x00000008;
510 
511 /// Specifies that the digital signature of the binary image must be checked at load time.
512 ///
513 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
514 pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: LOAD_LIBRARY_FLAGS = 0x00000080;
515 
516 /// Allow loading a DLL for execution from the current directory only if it is under a directory in
517 /// the Safe load list.
518 ///
519 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
520 pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: LOAD_LIBRARY_FLAGS = 0x00002000;
521