LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Problems with lParam in Win Message callback

I'm trying to automatically respond to the insertion of a USB memory stick in CVI 8.5.  I found some sample C# code that showed how to interpret the data returned for a WM_DEVICECHANGE message.  The problem is that when I cast the lParam returned to my callback to the appropriate structure, the data isn't correct.  I install the callback using:
 
 // install USB callback
 InstallWinMsgCallback (panelHandle, WM_DEVICECHANGE, UsbCallback, VAL_MODE_IN_QUEUE, NULL, &junk);
Note: I wan't quite sure about the usage of the last parameter, so I'm passing a junk integer.
 
My callback looks like this:
 
int CVICALLBACK UsbCallback (int panelHandle, int message, unsigned int* wParam, unsigned int* lParam, void* callbackData)
{
 struct _DEV_BROADCAST_HEADER *DeviceHeader = (struct _DEV_BROADCAST_HEADER *)lParam;
 unsigned int DeviceType = DeviceHeader->dbcd_devicetype;
 
 switch (*wParam)
 {
  case DBT_DEVICEARRIVAL:
   if (DeviceType == DBT_DEVTYP_VOLUME)
   {
    DEV_BROADCAST_VOLUME *DeviceHeader = (DEV_BROADCAST_VOLUME *)lParam;
    char DriveLetter = DriveMaskToLetter(DeviceHeader->dbcv_unitmask);
   } /* if-then */
   break;
 } /* switch */
 
 return 0;
} /*  UsbCallback */
The structures are defined in DBT.H, a Windows header I downloaded from MSDN.
 
When I insert my USB stick I get the DBT_DEVICE_ARRIVAL message.  But when I cast the lParam to the _DEV_BROADCAST_HEADER header, the data is all wrong.  The definition for this structure is:
 
struct _DEV_BROADCAST_HEADER { /* */
    DWORD       dbcd_size;
    DWORD       dbcd_devicetype;
    DWORD       dbcd_reserved;
};
According to MSDN, the size is supposed to be the size of the device and the type is one of the following:
 

DBT_DEVTYP_DEVICEINTERFACE 0x00000005

 

DBT_DEVTYP_HANDLE 0x00000006

 

DBT_DEVTYP_OEM 0x00000000

 

DBT_DEVTYP_PORT 0x00000003

 

DBT_DEVTYP_VOLUME 0x00000002

 
When I set a breakpoint inside the case statement, insert the key, and then exmaine the header structure I see this:
 
DeviceHeader->dbcd_size = 1244468
DeviceHeader->dbcd_devicetype = 4423667
 
The size is wrong (It's a 1GB stick) and the device type is an illegal value.
 
Am I casting the lParam incorrectly?  Is there some other step I have to take to extract the data from lParam?  When I install the callback, does the last parameter have anything to do with this?  Am I missing something obvious?
0 Kudos
Message 1 of 9
(6,660 Views)
ok, i see the problem: the event callback you register using InstallWinMsgCallback uses POINTERS to the lParam and wParam arguments (they are passed by reference). this is so you can modify the content of the message before it is passed to CVI User Interface Library.

the code you wrote is written for a standard windows event handler, for which wParam and lParam are passed by value.
now, try this (notice the * before lParam) and everything should be ok:
struct _DEV_BROADCAST_HEADER *DeviceHeader = (struct _DEV_BROADCAST_HEADER *)(*lParam);
DEV_BROADCAST_VOLUME *DeviceHeader = (DEV_BROADCAST_VOLUME *)(*lParam);

also, beware that the dbcd_size member of DEV_BROADCAST_HEADER represents the size of the data pointed to by lParam, not the size of the inserted device.
0 Kudos
Message 2 of 9
(6,636 Views)

(*lParam) is 0 so I get a NULL pointer reference.

Tony

0 Kudos
Message 3 of 9
(6,595 Views)
well, the above answer was only based on reading the code. so now, i checked it...

you are right, i also get a NULL pointer as both lParam and wParam. i tried with others Windows messages: WM_ACTIVATE does not work either, WM_CHAR works fine. strangely, the callback is called when the event occurs, so the callback has been registered correctly, but wParam and lParam are NULL.

i tried to find my way through toolbox.c to see where the problem is, but the message handler is not available. we only have access to the registration code, so i can't say... maybe someone from NI can explain the problem ?
0 Kudos
Message 4 of 9
(6,590 Views)
As dummy_decoy pointed out, there's some confusion coming from the discrepency between the wParam and lParam of the callback registered with InstallWinMsgCallback and those of the WndProc called by Windows. Really, the parameters to your UsbCallback would be better named pwParam and plParam, since they are pointers to wParam and lParam. You're properly accounting for this with wParam, as you're treating the dereferenced value as the event code. However, MSDN's documentation states that lParam is a "pointer to a structure...", and since your callback is passed a pointer to that, you need to dereference the parameter twice to get to the actual structure. I tested this with a random memory stick and got a valid structure. It was a device of type DBT_DEVTYP_OEM, which actually was not very informative.

Oh, and one more thing. You can actually edit and attach the source for the Programmer's Toolbox (toobox.c), so you can directly debug what's going on. Take a look at MsgHandlerWndProc; that's being set as the GWL_WNDPROC by a call to SetWindowLong and is directly called by Windows.

Mert A.
National Instruments


Message Edited by Mert A. on 04-30-2008 07:01 PM

Message Edited by Mert A. on 04-30-2008 07:05 PM
0 Kudos
Message 5 of 9
(6,573 Views)
ok, i caught it ! this is a bad side effect.

wParam and lParam are pointers, the corrected code i posted is correct. the problem is in the call to InstallWinMsgCallback: it uses the option VAL_MODE_IN_QUEUE

in this mode, the toolbox internally posts a deferred call. it means that the window procedure, which handles windows messages for our window, exits before the parameters are finally passed to our callback by the deferred call. since wParam and lParam are pointers to structures, they are destroyed once the window proc exits, thus are no more valid when our callback is called.

on the other hand, when using VAL_MODE_INTERCEPT, our callback is called straight away before the window proc exits, and lParam then points to a pointer to a perfectly valid structure containing the informations we are seeking.

this leads to a new advice that i hope will appear in the documentation: IF THE WINDOWS MESSAGE YOU WANT TO HANDLE USES POINTERS FOR LPARAM OR WPARAM, PLEASE DO NOT USE VAL_MODE_IN_QUEUE. and i hope that ignoring this advice do not lead to a GPF...

(thanks a lot Mert for the tip: i did not find MsgHandlerWndProc the first time, and i could not have debugged it without your help)
0 Kudos
Message 6 of 9
(6,562 Views)

Changing the callback mode to INTERCEPT solved the problem!  Thanks!

P.S. I second your comment that the help text for the InstallWinMsgCallback should explain this issue.



Message Edited by TonyG 614 on 05-01-2008 09:38 AM
0 Kudos
Message 7 of 9
(6,554 Views)
dummy_decoy and TonyG 614,

I think you're on to something with the necessity for inclusion of this in future releases and updates of the LabWindows/CVI help documents.  Would you mind creating a Product Suggestion for this?  You can even link directly back to this forum thread for reference.  All of the Product Suggestions that we receive are carefully reviewed and considered by members of our R&D teams.

In order to create Product Suggestions, just visit our Product Suggestion Center, or navigate to http://www.ni.com/contact and choose to give Product Feedback.
Derrick S.
Product Manager
NI DIAdem
National Instruments
0 Kudos
Message 8 of 9
(6,545 Views)
Done, and thanks for the suggestion.
0 Kudos
Message 9 of 9
(6,543 Views)