Skip to content

Commit

Permalink
Merge pull request #6 from TotemArts/dinput8_fix
Browse files Browse the repository at this point in the history
Work around dinput8.dll not existing in System32 by using COM
  • Loading branch information
DrChat authored Nov 14, 2023
2 parents 727ac03 + 084bb60 commit 8a1cf36
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ features = [
"interface",
"implement",
"Data_Xml_Dom",
"Win32_Devices_HumanInterfaceDevice",
"Win32_Foundation",
"Win32_Security",
"Win32_System_Com",
Expand Down
58 changes: 44 additions & 14 deletions src/dinput8.rs
Original file line number Diff line number Diff line change
@@ -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<IUnknown>,
_outer: Option<IUnknown>,
) -> 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<IUnknown, windows::core::Error> {
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
}
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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")?;

Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/xaudio27.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 8a1cf36

Please sign in to comment.