Use the exact data types and their architecture-specific sizes *EXACTLY* as they are defined in the function's signature as it is declared in the documentation. If you deviate from doing so in any way, the function will fail.
This code is wrong:
iStructWidth = iStructLen * iStructCount
hpRawInputDeviceList = BinaryAlloc ( iStructWidth )
"iStructCount" is undefined and any calculations based on it will produce wrong results.
You are still not correctly understanding what you are doing with allocating a buffer and then passing the pointer to the buffer as a parameter to the function. The function is going to write some data into that buffer. There are *2* parameters that you are going to pass that are pointers to buffers. One is the buffer that's going to receive one or more RAWINPUTDEVICELIST structures. At the start you don't know how many of those structures you are going to receive, so you have to call the function twice. The first call where you pass "lpnull" for the 1st parameter tells the function that you want it to tell you how many structures it will return. The number of structures gets written so a UINT that is passed by address [e.g. Pointer to UINT] in the 2nd parameter. Since you can't pass arbitrary numeric variables by a pointer in WinBatch, you have to allocate a binary buffer that is the size of a UINT [e.g. 4 bytes, same as a DWORD] and pass the buffer with "lpbinary:". After the first call, provided that the function's return value indicates success, you read the 4-byte unsigned integer [UINT] value *from* that buffer and use it to figure out how much memory to allocate for the binary buffer that you will pass as the 1st parameter the second time you call the function.
UINT GetRawInputDeviceList(
[out, optional] PRAWINPUTDEVICELIST pRawInputDeviceList, // lpnull on 1st call, lpbinary:<buffer-variable-name> on 2nd call
[in, out] PUINT puiNumDevices, // lpbinary:<buffer-for-uint-variable-name>
[in] UINT cbSize // just a normal WinBatch numeric variable with an integer value in it.
);
Make note of the return value of the function as defined in the online docs:
Return value
Type: UINT
If the function is successful, the return value is the number of devices stored in the buffer pointed to by pRawInputDeviceList.
On any other error, the function returns (UINT) -1 and GetLastError returns the error indication.
The definition of RAWINPUTDEVICELIST from the online docs:
typedef struct tagRAWINPUTDEVICELIST {
HANDLE hDevice; // 4 bytes on 32-bit, 8 bytes on 64-bit
DWORD dwType; // always 4 bytes
} RAWINPUTDEVICELIST, *PRAWINPUTDEVICELIST;
sizeof(RAWINPUTDEVICELIST) is 8 on 32-bit and 12 on 64-bit.
"*RAWINPUTDEVICELIST" means "Pointer to RAWINPUTDEVICELIST", the size of which varies only with the 32-bit/64-bit architecture, not with the size of RAWINPUTDEVICELIST itself.
The example code from the online docs:
UINT nDevices;
PRAWINPUTDEVICELIST pRawInputDeviceList = NULL;
while (true) {
if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { Error();}
if (nDevices == 0) { break; }
if ((pRawInputDeviceList = malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == NULL) {Error();}
nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST));
if (nDevices == (UINT)-1) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { Error(); }
// Devices were added.
free(pRawInputDeviceList);
continue;
}
break;
}
// do the job...
// after the job, free the RAWINPUTDEVICELIST
free(pRawInputDeviceList);
For now, ignore the fact that the function calls are made in a loop. The usage of a looping construct is there to deal with the possibility that a device is added or removed between the 1st & 2nd function calls and allows the code to re-try without blowing up or returning inaccurate information.
The first call to the function is:
GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)
With DllCall(), you'll pass "lpnull" for the 1st parameter.
The 2nd parameter will be passed with "lpbinary:" and the buffer will be 4 bytes in size.
The 3rd parameter will be the integer value 8 or 12 depending on the architecture, and it can be a literal numeric value or a variable set to that value.
The return value of the function will be -1 if it fails on the 1st call; otherwise it is successful.
You will need to learn to use the BinaryPeek*() functions to read a 4 byte unsigned integer from the buffer that you passed in as the 2nd parameter. That will get you the "nDevices" [e.g. "number of devices"] value that you multiply by the size of RAWINPUTDEVICELIST to determine what size binary buffer to allocate and pass as the 1st parameter the 2nd time you call the function.
The 2nd time the function is called, it looks like this [taken from example code above]:
nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST));
In this case, when you do the same with DllCall(), "pRawInputDeviceList" will be replaced with your 1st binary buffer passed via "lpbinary:<buffer-name>". The 2nd & 3rd parameters remain the same.
Note that the return value of the function can have 2 meanings this time. If it returns -1, then the function failed. Otherwise, the return value is the # of devices returned in the buffer that was passed at the 1st parameter.