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