• 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     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))]
27 mod 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 
53 use self::windows_imports::*;
54 use util::{ensure_compatible_types, cstr_cow_from_bytes};
55 use std::ffi::{OsStr, OsString};
56 use std::{fmt, io, marker, mem, ptr};
57 
58 /// The platform-specific counterpart of the cross-platform [`Library`](crate::Library).
59 pub struct Library(HMODULE);
60 
61 unsafe 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)
75 unsafe impl Sync for Library {}
76 
77 impl 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]
new<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error>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
this() -> Result<Library, crate::Error>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
open_already_loaded<P: AsRef<OsStr>>(filename: P) -> Result<Library, crate::Error>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.
load_with_flags<P: AsRef<OsStr>>(filename: P, flags: DWORD) -> Result<Library, crate::Error>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.
get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error>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.
get_ordinal<T>(&self, ordinal: WORD) -> Result<Symbol<T>, crate::Error>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.
into_raw(self) -> HMODULE258     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.
from_raw(handle: HMODULE) -> Library271     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.
close(self) -> Result<(), crate::Error>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 
297 impl Drop for Library {
drop(&mut self)298     fn drop(&mut self) {
299         unsafe { libloaderapi::FreeLibrary(self.0); }
300     }
301 }
302 
303 impl fmt::Debug for Library {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result304     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.
328 pub struct Symbol<T> {
329     pointer: FARPROC,
330     pd: marker::PhantomData<T>
331 }
332 
333 impl<T> Symbol<T> {
334     /// Convert the loaded `Symbol` into a handle.
into_raw(self) -> FARPROC335     pub fn into_raw(self) -> FARPROC {
336         self.pointer
337     }
338 }
339 
340 impl<T> Symbol<Option<T>> {
341     /// Lift Option out of the symbol.
lift_option(self) -> Option<Symbol<T>>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 
354 unsafe impl<T: Send> Send for Symbol<T> {}
355 unsafe impl<T: Sync> Sync for Symbol<T> {}
356 
357 impl<T> Clone for Symbol<T> {
clone(&self) -> Symbol<T>358     fn clone(&self) -> Symbol<T> {
359         Symbol { ..*self }
360     }
361 }
362 
363 impl<T> ::std::ops::Deref for Symbol<T> {
364     type Target = T;
deref(&self) -> &T365     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 
373 impl<T> fmt::Debug for Symbol<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result374     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
375         f.write_str(&format!("Symbol@{:p}", self.pointer))
376     }
377 }
378 
379 struct ErrorModeGuard(DWORD);
380 
381 impl ErrorModeGuard {
382     #[allow(clippy::if_same_then_else)]
new() -> Option<ErrorModeGuard>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 
401 impl Drop for ErrorModeGuard {
drop(&mut self)402     fn drop(&mut self) {
403         unsafe {
404             errhandlingapi::SetThreadErrorMode(self.0, ptr::null_mut());
405         }
406     }
407 }
408 
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>409 fn with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F)
410 -> Result<T, Option<crate::Error>>
411 where 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).
428 pub 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).
438 pub 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).
447 pub 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).
459 pub 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).
467 pub 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).
477 pub 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).
488 pub 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).
496 pub 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).
506 pub 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
521 pub 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).
526 pub 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).
532 pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;
533