使用 RIDI_DEVICENAME 的 GetRawInputDeviceInfo 返回无效内存

问题描述 投票:0回答:1

在我的代码中,我调用了

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 控制器尝试。

c++ winapi raw-input
1个回答
0
投票
使用此代码

工作正常: 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);

© www.soinside.com 2019 - 2024. All rights reserved.