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
/// A macro for creating dynamic library shims that can intercept and modify function calls.
///
/// The `shim` macro allows you to create a library that acts as a drop-in replacement for an existing library,
/// while providing the ability to hook and modify the behavior of exported functions.
///
/// # Usage
///
/// The macro takes a library name as an argument and is applied to a module. Within this module, you can define:
///
/// - An initialization function marked with `#[init]` that runs when the library is loaded
/// - Hook functions marked with `#[hook]` that intercept calls to specific exported functions
///
/// The original library's functions are available through the automatically generated `original` module.
///
/// # Example
///
/// This example creates a shim for `version.dll` that logs whenever `GetFileVersionInfoA` is called:
///
/// ```rust
/// #![feature(naked_functions)]
///
/// use cdylib_shim::shim;
///
/// #[shim("version.dll")]
/// mod version {
/// use std::{
/// ffi::{c_char, c_int, c_ulong, c_void},
/// fs::File,
/// };
///
/// #[init]
/// fn init() {
/// let file = File::create("version.log").unwrap();
///
/// tracing_subscriber::fmt()
/// .with_writer(file)
/// .with_ansi(false)
/// .init();
/// }
///
/// #[hook]
/// unsafe extern "system" fn GetFileVersionInfoA(
/// lptstrFileName: *const c_char,
/// dwHandle: c_ulong,
/// dwLen: c_ulong,
/// lpData: *const c_void,
/// ) -> c_int {
/// tracing::info!("Hello from GetFileVersionInfoA!");
/// unsafe { original::GetFileVersionInfoA(lptstrFileName, dwHandle, dwLen, lpData) }
/// }
/// }
/// ```
pub use shim;