在我的代码中,我调用了
GetRawInputDeviceInfo
函数,并传入 RIDI_DEVICENAME 命令。它应该用包含缓冲区名称的字符串填充第三个参数,并返回字符串的长度。
但是,当函数返回时,该参数指向无效内存(在调试器内显示
0x234449485c3f5c5c
,并且无法查看其内容)。
这是完整的代码:
#include <windows.h>
#include <stdint.h>
#define assert(x) do{if(!(x))__debugbreak();}while(0)
typedef size_t usize;
typedef uint8_t u8;
typedef unsigned int uint;
struct Raw_Input_Memory {
usize size;
usize used;
u8 *data;
};
#define raw_input_memory_push_array(memory, type, count) (type *)raw_input_memory_push_size(memory, sizeof(type) * count)
#define raw_input_memory_push_struct(memory, type) (type *)raw_input_memory_push_size(memory, sizeof(type))
void *raw_input_memory_push_size(Raw_Input_Memory *memory, usize size) {
assert(memory->used + size <= memory->size);
void *result = memory->data + memory->used;
memory->used += size;
return result;
}
int main() {
HINSTANCE module_instance = GetModuleHandle(NULL);
WNDCLASSA window_class = {};
window_class.lpfnWndProc = DefWindowProc;
window_class.hInstance = module_instance;
window_class.hCursor = LoadCursorA(NULL, IDC_ARROW);
window_class.lpszClassName = "Toplevel";
ATOM window_class_atom = RegisterClassA(&window_class);
if (window_class_atom) {
HWND window = CreateWindowA(window_class.lpszClassName, "Raw Input",
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, module_instance, NULL);
if (window) {
Raw_Input_Memory raw_input_memory = {};
raw_input_memory.size = 1024 * 1024;
raw_input_memory.used = 0;
raw_input_memory.data = (u8 *)VirtualAlloc(NULL, raw_input_memory.size,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
RAWINPUTDEVICE raw_input_device;
raw_input_device.usUsagePage = 0x01;
raw_input_device.usUsage = 0x05;
raw_input_device.dwFlags = 0;
raw_input_device.hwndTarget = 0;
if (RegisterRawInputDevices(&raw_input_device, 1,
sizeof(RAWINPUTDEVICE))) {
MSG window_message = {};
while (GetMessageA(&window_message, NULL, 0, 0) > 0) {
UINT message_kind = window_message.message;
WPARAM wparam = window_message.wParam;
LPARAM lparam = window_message.lParam;
switch (message_kind) {
case WM_QUIT: {
break;
} break;
case WM_INPUT: {
if (raw_input_memory.data) {
raw_input_memory.used = 0;
UINT input_size;
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &input_size,
sizeof(RAWINPUTHEADER)) != -1) {
RAWINPUT *input = (RAWINPUT *)raw_input_memory_push_size(&raw_input_memory,
input_size);
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, input,
&input_size, sizeof(RAWINPUTHEADER)) == input_size) {
assert(input->header.dwType == RIM_TYPEHID);
uint device_name_length = 128;
char *device_name = NULL;
device_name = raw_input_memory_push_array(&raw_input_memory, char,
device_name_length);
assert(device_name);
INT got_device_name = GetRawInputDeviceInfoA(input->header.hDevice,
RIDI_DEVICENAME,
&device_name,
&device_name_length);
if (got_device_name) {
/* ... */
}
}
}
}
} break;
default: {
TranslateMessage(&window_message);
DispatchMessageA(&window_message);
}
}
}
}
}
}
return 0;
}
请注意,调用并没有显式地失败:它不会返回 -1
也不是
0
,而是返回
83
;并且
GetLastError
返回
0
。我尝试过自己分配内存(正如您在我发布的代码中看到的那样)和传入 NULL 指针,两者都有相同的结果。我也尝试了宽版本,但仍然得到一个
83
作为返回值和指向
0x005c003f005c005c
的指针,该指针仍然无效。我做错了什么?为什么该函数向我传递无效内存以及如何阻止它这样做?我已经看到了
this 答案和 this other 答案,并阅读了文档。我不知道还能做什么。
顺便说一句,我正在用 PS4 控制器尝试。
工作正常:
UINT size = 0;
UINT result = ::GetRawInputDeviceInfoW(m_Handle, RIDI_DEVICENAME, nullptr, &size);
if (result == static_cast<UINT>(-1))
{
//PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
return false;
}
DCHECK_EQ(0u, result);
std::wstring buffer(size, 0);
result = ::GetRawInputDeviceInfoW(m_Handle, RIDI_DEVICENAME, buffer.data(), &size);
if (result == static_cast<UINT>(-1))
{
//PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
return false;
}
DCHECK_EQ(size, result);
m_InterfacePath = utf8::narrow(buffer);