錯誤現場
void DInputClass::GetInput() {
HRESULT hr = m_KeyboardDevice->GetDeviceState(sizeof(m_keyBuffer), (void**)&m_keyBuffer);
// ↑ 此處觸發 0xC0000005: 讀取位置 0x00000004 時發生訪問沖突
}
錯誤碼解讀
0xC0000005 = STATUS_ACCESS_VIOLATION,典型的空指針/野指針解引用
0x00000004 = 偏移量 4 字節,暗示訪問結構體/類的第 2 個成員(索引 1)
- 結合
m_KeyboardDevice->GetDeviceState(...),說明 m_KeyboardDevice 本身為 nullptr 或已釋放懸空指針
根因排查清單
- DirectInput 創建失敗未檢查:
DirectInput8Create、CreateDevice 返回值未驗證,導致 m_KeyboardDevice 為空
- 設備丟失未重置:設備被其他進程獨佔、系統休眠喚醒後,需調用
Acquire() 重新獲取,但代碼中 if(hr) 判斷邏輯反了(FAILED(hr) 才需重試)
- 線程安全問題:多線程並發調用
GetInput() 時,設備指針可能在別處被 Release()
- 對象生命週期管理:
DInputClass 構造函數中未初始化 m_KeyboardDevice = nullptr,析構函數未 Release()
修正代碼模板
HRESULT DInputClass::InitKeyboard(HWND hWnd) {
// 1. 創建 DirectInput 對象
HRESULT hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (void**)&m_pDI, NULL);
if (FAILED(hr)) return hr;
// 2. 創建鍵盤設備
hr = m_pDI->CreateDevice(GUID_SysKeyboard, &m_KeyboardDevice, NULL);
if (FAILED(hr)) return hr;
// 3. 設置數據格式
hr = m_KeyboardDevice->SetDataFormat(&c_dfDIKeyboard);
if (FAILED(hr)) return hr;
// 4. 設置協作級別
hr = m_KeyboardDevice->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (FAILED(hr)) return hr;
// 5. 獲取設備
hr = m_KeyboardDevice->Acquire();
return hr;
}
void DInputClass::GetInput() {
if (!m_KeyboardDevice) return; // 防禦性檢查
HRESULT hr = m_KeyboardDevice->GetDeviceState(sizeof(m_keyBuffer), m_keyBuffer);
if (FAILED(hr)) {
// 設備丟失:嘗試重新獲取
if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {
hr = m_KeyboardDevice->Acquire();
if (SUCCEEDED(hr)) {
m_KeyboardDevice->GetDeviceState(sizeof(m_keyBuffer), m_keyBuffer);
}
}
}
// 同理處理滑鼠...
}
調試技巧
- 在 Visual Studio 中啟用「異常設置」→ 勾選
Win32 Exceptions - c0000005,崩潰即斷點定位
- 給指針加上
__declspec(align(8)) 或使用 ComPtr<IDirectInputDevice8> 智能指針管理生命週期
- 輸出
hr 十六進制值對照 dinput.h 定義的 DIERR_* 錯誤碼