Windows-rs: XInputGetState causes STATUS_ACCESS_VIOLATION

Created on 26 May 2021  路  6Comments  路  Source: microsoft/windows-rs

The following snippet causes a STATUS_ACCESS_VIOLATION on exit. If I negate the conditional check, no error occurs. I can only assume that there is some kind of memory corruption occurring as a result of a controller actually being connected, but I'm at a loss as to why or how to fix it.

for i in 0..XUSER_MAX_COUNT {
    let mut controller_state = unsafe { std::mem::zeroed::<XINPUT_STATE>() };
    if unsafe { XInputGetState(i, &mut controller_state) == ERROR_SUCCESS.0 } {
        println!("{} {:?}", i, controller_state);
    } else {
        // Controller is not connected.
    }
}

Outputs:

0 XINPUT_STATE { dwPacketNumber: 11, Gamepad: XINPUT_GAMEPAD { wButtons: 0, bLeftTrigger: 0, bRightTrigger: 0, sThumbLX: -32768, sThumbLY: 0, sThumbRX: 0, sThumbRY: 0 } }
error: process didn't exit successfully: `target\debug\horizon.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)

A full example is available, which is basically a window with a direct copy of the Getting Controller State example from the XInput docs. Is this a problem with the bindings or my use of them?

question

All 6 comments

A quick check in C++ produces the same results, but as the docs are broken I have no idea whether the API is misbehaving or whether we're holding it wrong. @stevewhims may know what happened to the XInputGetState docs:

https://www.bing.com/search?q=XInputGetState

But as far as I can tell, the Rust bindings are not at fault.

Adding @karl-bridge-microsoft (and I sent him an email, too) as writer-owner of XInput.

@kennykerr, until the topics can be restored, you can see the content in the repo here: https://cpubwin.visualstudio.com/win32/_git/sdk-api?path=%2Fsdk-api-src%2Fcontent%2Fxinput.

Thanks Steve, looks like usage is also described here: https://docs.microsoft.com/en-us/windows/win32/xinput/getting-started-with-xinput

Anyway, this looks like an issue outside the scope of the Windows crate.

Thanks for confirming it's not a Windows crate issue. I've been able to get around the issue by loading XInput at runtime and creating a function pointer to XInputGetState. In case anyone else comes across this and want's a possible solution:

type XInputGetStateFn = extern "system" fn(u32, *mut XINPUT_STATE) -> u32;
extern "system" fn xinput_get_state_stub(_: u32, _: *mut XINPUT_STATE) -> u32 {
    return ERROR_DEVICE_NOT_CONNECTED.0;
}
#[allow(non_upper_case_globals)]
static mut XInputGetState: XInputGetStateFn = xinput_get_state_stub;

unsafe fn load_xinput() {
    let library = LoadLibraryW("xinput1_4.dll");
    if !library.is_null() {
        XInputGetState = std::mem::transmute(GetProcAddress(library, "XInputGetState"));
    }
}

Do you know where is best to raise this issue with XInput?

Hopefully @Karl-Bridge-Microsoft can help.

@kennykerr, @ambye85 - an engineering fix has resolved the doc issue you reported.

For XBox developer support, please try the Xbox Developer Forums.

Was this page helpful?
0 / 5 - 0 ratings