KaiserJohaan
KaiserJohaan

Reputation: 9240

RAWINPUT strange behaviour

I'm having some strange behaviour with RAWINPUT. The following code below WORKS:

case WM_INPUT:
{
     UINT rawInputSize;

     GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, nullptr, &rawInputSize, sizeof(RAWINPUTHEADER));

     LPBYTE inputBuffer = new BYTE[rawInputSize];

     GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, inputBuffer, &rawInputSize, sizeof(RAWINPUTHEADER));

     RAWINPUT* inp = (RAWINPUT*)inputBuffer;   // valid
}

But the following does NOT WORK:

case WM_INPUT:
{
     UINT rawInputSize;
     BYTE inputBuffer[40];

     GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, inputBuffer, &rawInputSize, sizeof(RAWINPUTHEADER));        // returns error code

     RAWINPUT* inp = (RAWINPUT*)inputBuffer;
}

Nor:

case WM_INPUT:
{
     UINT rawInputSize;
     RAWINPUT inputBuffer;

     GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, &inputBuffer, &rawInputSize, sizeof(RAWINPUTHEADER));      // returns error code
}

Both fails at GetRawInputData() which returns a general error code (with no details).

The working solution I posted first is not an option, I cannot do heap allocation at every keystroke or mouse action, I must use the stack.

Why does the two last fail?

Upvotes: 3

Views: 1562

Answers (1)

Yirkha
Yirkha

Reputation: 13828

The 4th parameter of GetRawInputData, pcbSize, has two functions. Upon entry, it specifies the length of the available buffer. Upon exit, it contains the length of the really used data. This is fairly common concept in Windows API.

In your first case, first call, the input value is not used and only the required length is stored there upon exit. The second call works, because the required length is still there.

But in your second and third example, you leave the variable uninitialized, so it contains random junk from the stack. Apparently something near 0, which makes the function fail. But that is just speculation, there are of course many ways how this can not work, crash etc.

You should initialize the variable like this:

RAWINPUT inputBuffer;
UINT rawInputSize = sizeof(inputBuffer);
GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, &inputBuffer, &rawInputSize, sizeof(RAWINPUTHEADER));

As a side-note, be careful when using that BYTE[] array as in your 2nd example -- some Alexander Belyakov made this helpful comment on the API docs page:

On Win64, GetRawInputData would return -1 with ERROR_NOACCESS, unless the pData buffer is aligned by 8 bytes.

Upvotes: 11

Related Questions