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::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 /// A 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 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 filled 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 path and with extension omitted,
86 /// `.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 initialization routines contained within the library are executed.
96 /// For the purposes of safety, 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 behaviour of `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 path and with extension omitted,
142 /// `.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 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 initialization routines contained within the library are executed.
182 /// For the purposes of safety, 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 function or static variable by symbol name.
210 ///
211 /// The `symbol` may not contain any null bytes, with an exception of 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. Using a
220 /// `Symbol` with a wrong type is undefined.
get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error>221 pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
222 ensure_compatible_types::<T, FARPROC>()?;
223 let symbol = cstr_cow_from_bytes(symbol)?;
224 with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
225 let symbol = libloaderapi::GetProcAddress(self.0, symbol.as_ptr());
226 if symbol.is_null() {
227 None
228 } else {
229 Some(Symbol {
230 pointer: symbol,
231 pd: marker::PhantomData
232 })
233 }
234 }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
235 }
236
237 /// Get a pointer to function or static variable by ordinal number.
238 ///
239 /// # Safety
240 ///
241 /// Users of this API must specify the correct type of the function or variable loaded. Using a
242 /// `Symbol` with a wrong type is undefined.
get_ordinal<T>(&self, ordinal: WORD) -> Result<Symbol<T>, crate::Error>243 pub unsafe fn get_ordinal<T>(&self, ordinal: WORD) -> Result<Symbol<T>, crate::Error> {
244 ensure_compatible_types::<T, FARPROC>()?;
245 with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
246 let ordinal = ordinal as usize as *mut _;
247 let symbol = libloaderapi::GetProcAddress(self.0, ordinal);
248 if symbol.is_null() {
249 None
250 } else {
251 Some(Symbol {
252 pointer: symbol,
253 pd: marker::PhantomData
254 })
255 }
256 }).map_err(|e| e.unwrap_or(crate::Error::GetProcAddressUnknown))
257 }
258
259 /// Convert the `Library` to a raw handle.
into_raw(self) -> HMODULE260 pub fn into_raw(self) -> HMODULE {
261 let handle = self.0;
262 mem::forget(self);
263 handle
264 }
265
266 /// Convert a raw handle to a `Library`.
267 ///
268 /// # Safety
269 ///
270 /// The handle shall be a result of a successful call of `LoadLibraryA`, `LoadLibraryW`,
271 /// `LoadLibraryExW`, `LoadLibraryExA` or a handle previously returned by the
272 /// `Library::into_raw` call.
from_raw(handle: HMODULE) -> Library273 pub unsafe fn from_raw(handle: HMODULE) -> Library {
274 Library(handle)
275 }
276
277 /// Unload the library.
278 ///
279 /// You only need to call this if you are interested in handling any errors that may arise when
280 /// library is unloaded. Otherwise this will be done when `Library` is dropped.
281 ///
282 /// The underlying data structures may still get leaked if an error does occur.
close(self) -> Result<(), crate::Error>283 pub fn close(self) -> Result<(), crate::Error> {
284 let result = with_get_last_error(|source| crate::Error::FreeLibrary { source }, || {
285 if unsafe { libloaderapi::FreeLibrary(self.0) == 0 } {
286 None
287 } else {
288 Some(())
289 }
290 }).map_err(|e| e.unwrap_or(crate::Error::FreeLibraryUnknown));
291 // While the library is not free'd yet in case of an error, there is no reason to try
292 // dropping it again, because all that will do is try calling `FreeLibrary` again. only
293 // this time it would ignore the return result, which we already seen failing…
294 std::mem::forget(self);
295 result
296 }
297 }
298
299 impl Drop for Library {
drop(&mut self)300 fn drop(&mut self) {
301 unsafe { libloaderapi::FreeLibrary(self.0); }
302 }
303 }
304
305 impl fmt::Debug for Library {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result306 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
307 unsafe {
308 // FIXME: use Maybeuninit::uninit_array when stable
309 let mut buf =
310 mem::MaybeUninit::<[mem::MaybeUninit::<WCHAR>; 1024]>::uninit().assume_init();
311 let len = libloaderapi::GetModuleFileNameW(self.0,
312 (&mut buf[..]).as_mut_ptr().cast(), 1024) as usize;
313 if len == 0 {
314 f.write_str(&format!("Library@{:p}", self.0))
315 } else {
316 let string: OsString = OsString::from_wide(
317 // FIXME: use Maybeuninit::slice_get_ref when stable
318 &*(&buf[..len] as *const [_] as *const [WCHAR])
319 );
320 f.write_str(&format!("Library@{:p} from {:?}", self.0, string))
321 }
322 }
323 }
324 }
325
326 /// Symbol from a library.
327 ///
328 /// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
329 /// `Symbol` does not outlive `Library` it comes from.
330 pub struct Symbol<T> {
331 pointer: FARPROC,
332 pd: marker::PhantomData<T>
333 }
334
335 impl<T> Symbol<T> {
336 /// Convert the loaded Symbol into a handle.
into_raw(self) -> FARPROC337 pub fn into_raw(self) -> FARPROC {
338 let pointer = self.pointer;
339 mem::forget(self);
340 pointer
341 }
342 }
343
344 impl<T> Symbol<Option<T>> {
345 /// Lift Option out of the symbol.
lift_option(self) -> Option<Symbol<T>>346 pub fn lift_option(self) -> Option<Symbol<T>> {
347 if self.pointer.is_null() {
348 None
349 } else {
350 Some(Symbol {
351 pointer: self.pointer,
352 pd: marker::PhantomData,
353 })
354 }
355 }
356 }
357
358 unsafe impl<T: Send> Send for Symbol<T> {}
359 unsafe impl<T: Sync> Sync for Symbol<T> {}
360
361 impl<T> Clone for Symbol<T> {
clone(&self) -> Symbol<T>362 fn clone(&self) -> Symbol<T> {
363 Symbol { ..*self }
364 }
365 }
366
367 impl<T> ::std::ops::Deref for Symbol<T> {
368 type Target = T;
deref(&self) -> &T369 fn deref(&self) -> &T {
370 unsafe {
371 // Additional reference level for a dereference on `deref` return value.
372 &*(&self.pointer as *const *mut _ as *const T)
373 }
374 }
375 }
376
377 impl<T> fmt::Debug for Symbol<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result378 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
379 f.write_str(&format!("Symbol@{:p}", self.pointer))
380 }
381 }
382
383 struct ErrorModeGuard(DWORD);
384
385 impl ErrorModeGuard {
386 #[allow(clippy::if_same_then_else)]
new() -> Option<ErrorModeGuard>387 fn new() -> Option<ErrorModeGuard> {
388 unsafe {
389 let mut previous_mode = 0;
390 if errhandlingapi::SetThreadErrorMode(SEM_FAILCE, &mut previous_mode) == 0 {
391 // How in the world is it possible for what is essentially a simple variable swap
392 // to fail? For now we just ignore the error -- the worst that can happen here is
393 // the previous mode staying on and user seeing a dialog error on older Windows
394 // machines.
395 None
396 } else if previous_mode == SEM_FAILCE {
397 None
398 } else {
399 Some(ErrorModeGuard(previous_mode))
400 }
401 }
402 }
403 }
404
405 impl Drop for ErrorModeGuard {
drop(&mut self)406 fn drop(&mut self) {
407 unsafe {
408 errhandlingapi::SetThreadErrorMode(self.0, ptr::null_mut());
409 }
410 }
411 }
412
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>413 fn with_get_last_error<T, F>(wrap: fn(crate::error::WindowsError) -> crate::Error, closure: F)
414 -> Result<T, Option<crate::Error>>
415 where F: FnOnce() -> Option<T> {
416 closure().ok_or_else(|| {
417 let error = unsafe { errhandlingapi::GetLastError() };
418 if error == 0 {
419 None
420 } else {
421 Some(wrap(crate::error::WindowsError(io::Error::from_raw_os_error(error as i32))))
422 }
423 })
424 }
425
426 /// Do not check AppLocker rules or apply Software Restriction Policies for the DLL.
427 ///
428 /// This action applies only to the DLL being loaded and not to its dependencies. This value is
429 /// recommended for use in setup programs that must run extracted DLLs during installation.
430 ///
431 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
432 pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL;
433
434 /// Map the file into the calling process’ virtual address space as if it were a data file.
435 ///
436 /// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call
437 /// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only
438 /// memory to raise an access violation. Use this flag when you want to load a DLL only to extract
439 /// messages or resources from it.
440 ///
441 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
442 pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE;
443
444 /// Map the file into the calling process’ virtual address space as if it were a data file.
445 ///
446 /// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive
447 /// write access for the calling process. Other processes cannot open the DLL file for write access
448 /// while it is in use. However, the DLL can still be opened by other processes.
449 ///
450 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
451 pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
452
453 /// Map the file into the process’ virtual address space as an image file.
454 ///
455 /// The loader does not load the static imports or perform the other usual initialization steps.
456 /// Use this flag when you want to load a DLL only to extract messages or resources from it.
457 ///
458 /// Unless the application depends on the file having the in-memory layout of an image, this value
459 /// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or
460 /// [`LOAD_LIBRARY_AS_DATAFILE`].
461 ///
462 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
463 pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE;
464
465 /// Search application's installation directory for the DLL and its dependencies.
466 ///
467 /// Directories in the standard search path are not searched. This value cannot be combined with
468 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
469 ///
470 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
471 pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
472
473 /// Search default directories when looking for the DLL and its dependencies.
474 ///
475 /// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`],
476 /// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the
477 /// standard search path are not searched. This value cannot be combined with
478 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
479 ///
480 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
481 pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
482
483 /// Directory that contains the DLL is temporarily added to the beginning of the list of
484 /// directories that are searched for the DLL’s dependencies.
485 ///
486 /// Directories in the standard search path are not searched.
487 ///
488 /// The `filename` parameter must specify a fully qualified path. This value cannot be combined
489 /// with [`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_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
493
494 /// Search `%windows%\system32` for the DLL and its dependencies.
495 ///
496 /// Directories in the standard search path are not searched. This value cannot be combined with
497 /// [`LOAD_WITH_ALTERED_SEARCH_PATH`].
498 ///
499 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
500 pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32;
501
502 /// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched
503 /// for the DLL and its dependencies.
504 ///
505 /// If more than one directory has been added, the order in which the directories are searched is
506 /// unspecified. Directories in the standard search path are not searched. This value cannot be
507 /// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`].
508 ///
509 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
510 pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS;
511
512 /// If `filename specifies an absolute path, the system uses the alternate file search strategy
513 /// discussed in the [Remarks section] to find associated executable modules that the specified
514 /// module causes to be loaded.
515 ///
516 /// If this value is used and `filename` specifies a relative path, the behavior is undefined.
517 ///
518 /// If this value is not used, or if `filename` does not specify a path, the system uses the
519 /// standard search strategy discussed in the [Remarks section] to find associated executable
520 /// modules that the specified module causes to be loaded.
521 ///
522 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
523 ///
524 /// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks
525 pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH;
526
527 /// Specifies that the digital signature of the binary image must be checked at load time.
528 ///
529 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
530 pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
531
532 /// Allow loading a DLL for execution from the current directory only if it is under a directory in
533 /// the Safe load list.
534 ///
535 /// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters).
536 pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS;
537