diff --git a/Cargo.toml b/Cargo.toml index 293df6e..023922a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ features = [ "interface", "implement", "Data_Xml_Dom", + "Win32_Devices_HumanInterfaceDevice", "Win32_Foundation", "Win32_Security", "Win32_System_Com", diff --git a/src/dinput8.rs b/src/dinput8.rs index 1f14002..a8863d2 100644 --- a/src/dinput8.rs +++ b/src/dinput8.rs @@ -1,22 +1,52 @@ //! This module handles functionality related to the original dinput8.dll -use lazy_static::lazy_static; -use libloading::Library; - -lazy_static! { - static ref DINPUT8_DLL: Library = unsafe { Library::new("C:\\Windows\\System32\\dinput8.dll") }.unwrap(); - static ref DINPUT8CREATE_PTR: libloading::Symbol<'static, unsafe extern "C" fn(usize, u32, usize, usize, usize) -> u32> = - unsafe { DINPUT8_DLL.get(b"DirectInput8Create\0") }.unwrap(); -} +use windows::{ + core::{IUnknown, Interface, GUID, HRESULT}, + Win32::{ + Devices::HumanInterfaceDevice::{CLSID_DirectInput8, IDirectInput8A, IDirectInput8W}, + Foundation::{E_NOINTERFACE, HINSTANCE, S_OK}, + System::Com::{CoCreateInstance, CLSCTX_INPROC_SERVER}, + }, +}; /// This function simply redirects the one and only DirectInput8Create call to the real dinput8 DLL. #[no_mangle] #[export_name = "DirectInput8Create"] pub unsafe extern "C" fn directinput8_create( - hinst: usize, + hinst: HINSTANCE, dwversion: u32, - riid: usize, - out: usize, - outer: usize, -) -> u32 { - (DINPUT8CREATE_PTR)(hinst, dwversion, riid, out, outer) + riid: *const GUID, + out: *mut Option, + _outer: Option, +) -> HRESULT { + // Instead of trying to load the original dinput8.dll and calling the original `DirectInput8Create`, + // we can simply load the dinput8 interface via COM and return it up to our caller. This is basically + // what DirectInput8Create does noawadays anyway. + // + // Reference: https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416756(v=vs.85) + let f = || -> Result { + match unsafe { riid.as_ref() } { + Some(&IDirectInput8A::IID) => { + let dinput: IDirectInput8A = + CoCreateInstance(&CLSID_DirectInput8, None, CLSCTX_INPROC_SERVER)?; + + dinput.Initialize(hinst, dwversion)?; + Ok(dinput.cast()?) + } + Some(&IDirectInput8W::IID) => { + let dinput: IDirectInput8W = + CoCreateInstance(&CLSID_DirectInput8, None, CLSCTX_INPROC_SERVER)?; + + dinput.Initialize(hinst, dwversion)?; + Ok(dinput.cast()?) + } + _ => return Err(E_NOINTERFACE.into()), + } + }; + + *out = match f() { + Ok(v) => Some(v), + Err(e) => return e.code(), + }; + + S_OK } diff --git a/src/lib.rs b/src/lib.rs index 5527ed9..c3b9c3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ use anyhow::Context; use sha2::{Digest, Sha256}; use windows::core::PCWSTR; +use windows::Win32::System::Com::{CoInitializeEx, COINIT_MULTITHREADED}; use windows::Win32::{ Foundation::{HANDLE, HINSTANCE}, System::{ @@ -94,6 +95,9 @@ fn get_module_slice(info: &MODULEINFO) -> *const [u8] { /// Called upon DLL attach. This function verifies the UDK and initializes /// hooks if the UDK matches our known hash. fn dll_attach() -> anyhow::Result<()> { + // Ensure that COM is initialized. + unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) }.context("failed to initialize COM")?; + let process = unsafe { GetCurrentProcess() }; let module = unsafe { GetModuleHandleA(None) }.context("failed to get module handle")?; @@ -140,6 +144,7 @@ pub extern "stdcall" fn DllMain( DLL_PROCESS_ATTACH => { if let Err(e) = dll_attach() { // Print a debug message for anyone who's listening. + output_debug_string(&format!("{:?}\n", e)); eprintln!("{:?}", e); } } diff --git a/src/xaudio27.rs b/src/xaudio27.rs index 702ffa1..45e131b 100644 --- a/src/xaudio27.rs +++ b/src/xaudio27.rs @@ -26,7 +26,7 @@ fn debug_log(msg: std::fmt::Arguments) { // Only bother logging when debug assertions are on. #[cfg(debug_assertions)] { - use windows::core::PCSWSTR; + use windows::core::PCWSTR; use windows::Win32::System::Diagnostics::Debug::OutputDebugStringW; // OutputDebugString does not append newlines.