1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
mod windows_dll_impl; extern crate proc_macro; use proc_macro::TokenStream; use windows_dll_impl::parse_windows_dll; /// # Dynamically load functions from a windows dll /// /// Works on extern blocks containing only functions, e.g: /// ``` /// #[dll("user32.dll")] /// extern "system" { /// #[allow(non_snake_case)] /// fn SetWindowCompositionAttribute(h_wnd: HWND, data: *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL; /// } /// ``` /// The `.dll` file extension can be omitted if the dll name has no path, e.g /// ``` /// #[dll("user32")] /// extern "system" { /// ... /// } /// ``` /// if the dll name is a valid rust identifier, you can also omit the quotes, e.g: /// ``` /// #[dll(user32)] /// extern "system" { /// ... /// } /// ``` /// /// For each function declaration, an unsafe rust wrapper function will be generated /// which dynamically loads the original function from the dll. /// /// ## Rename /// If you need to give the rust function a different name /// you can manually specify the dll symbol to load, /// Just put the dll symbol name in a **`#[link_name]`** attribute, e.g: /// ``` /// #[dll(user32)] /// extern "system" { /// #[link_name = "SetWindowCompositionAttribute"] /// fn set_window_composition_attribute(h_wnd: HWND, data: *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL; /// } /// ``` /// /// ## Ordinal exports /// If you need to load a function that is exported by ordinal /// you can put the ordinal in a **`#[link_ordinal]`** attribute, e.g: /// ``` /// #[dll(uxtheme)] /// extern "system" { /// #[link_ordinal = 133] /// fn allow_dark_mode_for_window(hwnd: HWND, allow: BOOL) -> BOOL; /// } /// ``` /// /// ## Error handling /// By default the generated functions panic when the dll function cannot be loaded /// you can check if they exist by calling `function_name::exists()` which returns a `bool`, e.g: /// ``` /// if allow_dark_mode_for_window::exists() { /// allow_dark_mode_for_window(hwnd, allow) /// } /// ``` /// /// You can also generate a wrapper function which returns a `Result<T, windows_dll::Error<function_name>>` /// To better integrate with the **`?`** operator, Just put a **`#[fallible]`** attribute /// on the function declaration, e.g: /// ``` /// #[dll(user32)] /// extern "system" { /// #[allow(non_snake_case)] /// #[fallible] /// fn SetWindowCompositionAttribute(h_wnd: HWND, data: *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL; /// } /// fn main() -> Result<(), Box<dyn Error>> { /// ... /// let result: Result<BOOL, windows_dll::Error<SetWindowCompositionAttribute>> = SetWindowCompositionAttribute(h_wnd, data); /// ... /// } /// ``` /// /// # LoadLibraryExW flags /// This library uses the Win32 API function /// [LoadLibraryExW](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw) /// internally. You can pass flags to the dwFlags parameter /// by passing a second argument to the **`#[dll]`** attribute, e.g /// ``` /// #[dll(bcrypt, LOAD_LIBRARY_SEARCH_SYSTEM32)] /// extern "system" { /// #[link_name = "BCryptAddContextFunction"] /// fn bcrypt_add_context_function(dw_table: ULONG, psz_context: LPCWSTR, dw_interface: ULONG, psz_function: LPCWSTR, dw_position: ULONG) -> BOOL; /// } /// ``` /// Available flags are re-exported from the **`flags`** module #[proc_macro_attribute] pub fn dll(metadata: TokenStream, input: TokenStream) -> TokenStream { parse_windows_dll(metadata, input) .unwrap_or_else(|err| err.to_compile_error()) .into() }