08-05-2014 08:45 AM
Hi,
I want to call GetRawInputeviceList function in the User32.dll using LabVIEW, but I am having difficulty in understandign the function prototype. To be specific, I am not clear what LabVIEW data types to be created for the arguments in the function. I went through this link http://msdn.microsoft.com/en-us/library/windows/desktop/ms645598(v=vs.85).aspx to understand the function prototype, but it is confusing.
Thanks
08-05-2014 10:08 AM - edited 08-05-2014 10:20 AM
I created a LabVIEW Example based off of the example on the MSDN.
Most of the datatypes for this example boil down to unsigned ints 32-bit. See Windows Data Types for more info. It should also be noted that I use a hardcoded "8" for the sizeof(RAWINPUTDEVICELIST). This is because each of the child elements are 4-byte integers. You could check this by downloading Visual Studio and using "printf("%d\n", sizeof(RAWINPUTDEVICELIST);".
C++:
The following sample code shows a typical call to GetRawInputDeviceList:
UINT nDevices; PRAWINPUTDEVICELIST pRawInputDeviceList; if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { Error();} if ((pRawInputDeviceList = malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == NULL) {Error();} if (GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST)) == (<dtype rid="UINT"/>)-1) {Error();} // do the job... // after the job, free the RAWINPUTDEVICELIST free(pRawInputDeviceList);
LabVIEW:
In case the snippet doesn't work, I also attached the VI.
*Note: It should also be noted that my error checking is very minimal. I check for the "-1" output on the first call to the function, but I really should use the Kernel32.dll to call GetLastError() as necessary. This is obviously a simplistic example.
EDIT:
If you have any specific questions about the code or function prototyping, feel free to ask. I'll be honest, this example took me a long while to replicate. Getting the structure to pass correctly took some trial-and-error 😛
08-06-2014 12:35 AM
Hi,
Thanks a lot for the VI, but I am not able to open it. I have LabVIEW version 12.0.1. Could you post the VI for version 12.0.1?
Thanks
08-06-2014 06:27 AM - edited 08-06-2014 06:54 AM
@Flamboyant wrote:
Hi,
Thanks a lot for the VI, but I am not able to open it. I have LabVIEW version 12.0.1. Could you post the VI for version 12.0.1?
Thanks
Sure thing. Give this attachment a try. It should be in LabVIEW 2012 format.
Please let me know if you have any problems or questions!
EDIT:
I actually found a bug in the program. See my next post for an updated VI in 2012 format.
08-06-2014 07:01 AM - edited 08-06-2014 07:03 AM
Sorry for that... The case structure was incorrect in my original example 😛
The output of GetRawInputDeviceList is always -1 from the first call, even when it correctly returns a value in the puiNumDevices. As a result, you would need to use Kernel32.dll to check GetLastError in order to determine if it worked correctly or not.
Note: The program may say it cannot find the path to "user32.dll". If so, manually navigate to where you have it located. On most installs it should be in C:\Windows\System32\User32.dll
08-06-2014 02:04 PM - edited 08-06-2014 02:13 PM
A few remarks:
HANDLE is a pointer sized datatype, so it is 4 bytes in a 32 bit Windows application, but 8 bytes in a 64 bit application. Because of alignment which will align the handle in each array element to its own size the array element therefore should be in LabVIEW 32 bit two uint32 but in LabVIEW 64 Bit an uint64 for the handle, then an uint32 for the dwType and another uint32 which is a filler.
The problem with the path to user32.dll is because you should NOT enter the entire path in the Call Library Node configuration but only the DLL name alone. Therefore change it to "user32.dll" without any path.
Also use of GetLastError() is problematic in LabVIEW. Windows maintains a last error value per thread. LabVIEW is inherently multithreading. In this case the Call Library Nodes are configured to execute the call in the single threaded LabVIEW UI execution system which might seem like it will cirmumvent this problem nicely. BUT: Between the call to GetRawInputDevice() and the GetLastError() function LabVIEW is VERY likely to call quite a few other Windows API functions which might change the last error value for this thread. It is after all the UI thread which LabVIEW uses for anything user interface related and many of those functions do influence the last error value. Reliance on a correct GetLastError() value is not possible in LabVIEW if you do all the Windows API calls only through Call Library Nodes. The only way to make sure that GetLastError() returns the actual meaningful value for an API call is by creating an external shared library that packs the API call and the GetLastError() call into the same function.
08-06-2014 02:21 PM
@rolfk wrote:
A few remarks:
HANDLE is a pointer sized datatype, so it is 4 bytes in a 32 bit Windows application, but 8 bytes in a 64 bit application. Because of alignment which will align the handle in each array element to its own size the array element therefore should be in LabVIEW 32 bit two uint32 but in LabVIEW 64 Bit an uint64 for the handle, then an uint32 for the dwType and another uint32 which is a filler.
The problem with the path to user32.dll is because you should NOT enter the entire path in the Call Library Node configuration but only the DLL name alone. Therefore change it to "user32.dll" without any path.
Also use of GetLastError() is problematic in LabVIEW. Windows maintains a last error value per thread. LabVIEW is inherently multithreading. In this case the Call Library Nodes are configured to execute the call in the single threaded LabVIEW UI execution system which might seem like it will cirmumvent this problem nicely. BUT: Between the call to GetRawInputDevice() and the GetLastError() function LabVIEW is VERY likely to call quite a few other Windows API functions which might change the last error value for this thread. It is after all the UI thread which LabVIEW uses for anything user interface related and many of those functions do influence the last error value. Reliance on a correct GetLastError() value is not possible in LabVIEW if you do all the Windows API calls only through Call Library Nodes. The only way to make sure that GetLastError() returns the actual meaningful value for an API call is by creating an external shared library that packs the API call and the GetLastError() call into the same function.
Great information, most of which I didn't know! Quoted again for truth.