GetRawInputDeviceInfo with RIDI_DEVICENAME returns invalid memory

139 views Asked by At

In my code I have a call to the GetRawInputDeviceInfo function, passing in the RIDI_DEVICENAME command. It is supposed to fill the 3rd parameter with a string containing the name of the buffer, and return the length of the string.

However, when the function returns, that parameter points to invalid memory (inside the debugger it says 0x234449485c3f5c5c, and can't view the contents of it).

This is the complete code:

#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;
}

Note that the call doesn't explicitly fail: it doesn't return -1 nor 0, but 83; and GetLastError returns 0.

I've tried both allocating the memory myself (as you can see in the code I posted) and passing in a NULL pointer, and both have the same result. I tried the wide version too, and I still get an 83 as a return value and a pointer to 0x005c003f005c005c, which is still invalid.

What am I doing wrong? Why does the function pass me invalid memory and how do I stop it from doing so? I've seen this answer, and this other answer, and read the docs. I don't know what else to do.

By the way, I'm trying it with a PS4 controller.

0

There are 0 answers