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