{"id":878,"date":"2013-04-18T10:00:00","date_gmt":"2013-04-18T04:30:00","guid":{"rendered":"http:\/\/www.e-consystems.com\/blog\/windowsce\/?p=878"},"modified":"2023-08-15T12:31:28","modified_gmt":"2023-08-15T07:01:28","slug":"retrieving-usb-vidpid-in-application-on-windows-ce-6-07-0","status":"publish","type":"post","link":"https:\/\/www.e-consystems.com\/blog\/windowsce\/retrieving-usb-vidpid-in-application-on-windows-ce-6-07-0\/","title":{"rendered":"Retrieving USB VID\/PID in application on WinCE 6.0\/7.0"},"content":{"rendered":"<p>Every windows embedded developer knows that Windows CE is used for customized devices and some requirements demanded from the customers to restrict certain USB devices based on the Vendor ID (VID) or Product ID(PID). Device has to respond only to their USB accessories, for example, Customer has designed their own USB HID device accessories for their devices and  expected to respond only for their accessories. Even with their accessories they are introducing special featured accessories and expecting the device (application) to act accordingly for each accessory dynamically. So we need to take some decision on the application which requires some unique ID(VID\/PID) to identify the connected accessory.<\/p>\n<p>When a USB device is plugged or unplugged,  Windows CE doesn\u2019t not support applications to retrieve the Vendor ID and  Product ID of USB devices directly using through APIs or WinProc Messages like  PC. At the maximum we can retrieve the driver prefixes for the  plugged\/unplugged devices through some APIs.<\/p>\n<p>Since Windows CE is a customizable OS, we can play  around the USB Host driver to support this feature up to an extend (Our case we  need VID\/PID and interface protocol information of HID devices).We planned the  same way to retrieve the VID\/PID information like PC application through <strong>WinProc<\/strong> Messages to avoid complexity. \u00a0Let us see the interesting stubs.<\/p>\n<p><strong>USB host driver changes<\/strong><br \/>\nWe used <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee500168%28v=winembedded.60%29.aspx\">SendNotifyMessage<\/a>()  API to broadcast the device information from the driver to application so that  this will be received in WinProc which could be easy to handle. We tried  various messages and finally we succeed with the following message.<\/p>\n<p><strong> Message  broadcast when device plugged<\/strong><\/p>\n<ul><em>SendNotifyMessage(HWND_BROADCAST,WM_DEVICECHANGE,\u00a0 DBT_DEVICEARRIVAL,(LPARAM)&amp;UserData);<\/em><\/ul>\n<p><strong>Message broadcast when device unplugged<\/strong><\/p>\n<ul> <em>SendNotifyMessage(HWND_BROADCAST,WM_DEVICECHANGE,  DBT_DEVICEREMOVECOMPLETE,(LPARAM)&amp;UserData);<\/em><\/ul>\n<p>Here the <strong>UserData<\/strong> is the user defined structure  we are using to pass the VID \/PID and required data to application from driver.<\/p>\n<ul> <em>typedef struct _DEVICE_VID_PID_INFO {<\/em><br \/>\n<em> DWORD\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dev_size;<\/em><br \/>\n<em> DWORD\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dev_vid;<\/em><br \/>\n<em> DWORD\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dev_pid;<\/em><br \/>\n<em> DWORD\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dev_InterfaceProtocol;<\/em><br \/>\n<em> }  DEVICE_VID_PID_INFO;<\/em><br \/>\n<em>DEVICE_VID_PID_INFO UserData;<\/em><\/ul>\n<p>Now we need to  know where to add the SendNotifyMessage in USB Host driver. Since we are using  high speed EHCI host, we have cloned the corresponding USB Host driver from the  \\WINCE600\\PUBLIC\\COMMON\\OAK\\DRIVERS\\USB\\HCD\\USB20\\USB2COM directory to our BSP.  We have to play with some functions in cdevice.cpp file.<br \/>\nWhenever the USB  device is plugged, the CHub::AttachDevice() will be called and all descriptors  will be received in this function through the series of\u00a0 calls to GetDescriptor() function in various  cases. VID\/PID will be received in device descriptor but we need  InterfaceProtocol information to identify more about our HID devices (our case)  which is in the interface descriptor, we have received the necessary  information in the DEVICE_CONFIG_STATUS_DETERMINE_CONFIG_TO_CHOOSE, this case  will be called after the DEVICE_CONFIG_STATUS_SCHEDULING_GET_CONFIG_DESCRIPTOR  case in this AttachDevice() function. You can see the structure <strong>deviceInfo <\/strong>on the function which  contains the required data.<br \/>\n<em>USB_DEVICE_INFO\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0  deviceInfo;<\/em><br \/>\nAbove structure  has the necessary device information that you need. I have shared the code  snippet of CHub::AttachDevice() for your reference.<\/p>\n<ul><em>case  DEVICE_CONFIG_STATUS_DETERMINE_CONFIG_TO_CHOOSE:<\/em><br \/>\n<em> { <\/em><br \/>\n<em> \u2026.<\/em><br \/>\n<em> \u2026.<\/em><br \/>\n<em> \/*End of  this case call our function to send notification*\/<\/em><br \/>\n<em> <strong>BroadCastDeviceInfo(deviceInfo,TRUE);<\/strong> \/\/TRUE means attached<\/em><br \/>\n<em> break;<\/em><br \/>\n<em> }<\/em><\/ul>\n<p>We have written  a separate function for broadcasting the device information which will be used  both in attach and detach. We have called the <strong>BroadCastDeviceInfo()<\/strong> function in CFunction::HandleDetach() When  the device is detached.<\/p>\n<ul><em>void CFunction::HandleDetach( void )<\/em><br \/>\n<em>{<\/em><br \/>\n<em> DEBUGMSG(  ZONE_ATTACH || ZONE_FUNCTION, (TEXT(&#8220;+CFunction(tier  %d)::HandleDetach\\n&#8221;), m_tierNumber) );<\/em><br \/>\n<em> <strong>BroadCastDeviceInfo(m_deviceInfo,FALSE); <\/strong>\/\/FALSE  means detached<\/em><br \/>\n<em> \u2026..<\/em><br \/>\n<em> \u2026..<br \/>\n}<\/em><\/ul>\n<p>Next is the  actual function, which we are passing messages to application. Function  arguments are the USB_DEVICE_INFO structure and device status (attach or  detach).<\/p>\n<ul><em>void BroadCastDeviceInfo(USB_DEVICE_INFO deviceInfo,BOOL  IsAttached)<\/em><br \/>\n<em>{<\/em><br \/>\n<em>DEVICE_VID_PID_INFO UserData;<\/em><br \/>\n<em>DWORD Return=WaitForAPIReady(SH_WMGR,200); <\/em><br \/>\n<em>\/\/This is must. Since the SendNotifyMessage is \/\/ the  Window Manger API and this won\u2019t be available during boot and need to skip the <\/em><br \/>\n<em>\/\/ SendNotifyMessage call otherwise exception will happen.<\/em><br \/>\n<em> switch(Return)<\/em><br \/>\n<em> {<\/em><br \/>\n<em> case  WAIT_OBJECT_0:<\/em><br \/>\n<em> {<\/em><br \/>\n<em> UserData.dev_size = (sizeof(  DEVICE_VID_PID_INFO));<\/em><br \/>\n<em> UserData.dev_pid = deviceInfo.Descriptor.idProduct;<\/em><br \/>\n<em> UserData.dev_vid =\u00a0 deviceInfo.Descriptor.idVendor;<\/em><br \/>\n<em> UserData.dev_InterfaceProtocol=deviceInfo.lpActiveConfig-&gt;lpInterfaces-&gt;  Descriptor.bInterfaceProtocol;<\/em><br \/>\n<em> if(IsAttached)<\/em><br \/>\n<em> SendNotifyMessage(HWND_BROADCAST,WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&amp;UserData);<\/em><br \/>\n<em> else<\/em><br \/>\n<em> SendNotifyMessage(HWND_BROADCAST,WM_DEVICECHANGE,  DBT_DEVICEREMOVECOMPLETE,(LPARAM)&amp;UserData);<\/em><br \/>\n<em> }<\/em><br \/>\n<em> break;<\/em><br \/>\n<em> case  WAIT_TIMEOUT:<\/em><br \/>\n<em> case  WAIT_FAILED:<\/em><br \/>\n<em> {<\/em><br \/>\n<em> RETAILMSG(1,(TEXT(&#8221;  Skipped SendNotifyMessage&#8230;&#8230;&#8230;&#8230;\\r\\n&#8221;)));<\/em><br \/>\n<em> }<\/em><br \/>\n<em> break;<\/em><br \/>\n<em> }<br \/>\n<\/em><br \/>\n<em>}<\/em><\/ul>\n<p><strong>SendNotifyMessage()<\/strong> function is a Window Manger function and  which will not be ready during the boot time since USB Host driver will be  loaded earlier than window Manager. \u00a0Suppose  if the device is attached during boot time, calling this API will end with  fatal. So we have to check whether this API is ready to call using<strong> WaitForAPIReady()<\/strong> before calling this API(As shown in the above  code).if it is not ready you have to skip the call. Since we are skipping the  API call, application won\u2019t get message about this attach\/detach during this  case. In this case, we can save\/delete the necessary information in user  defined registry when the device is attached or detached respectively. When  launching the application, it has to check for these predefined registry  entries and act accordingly. Once the API is ready, after that we can get  notification to application. Now Let us see how can we receive the VID\/PID  during device attach\/detach in application.<\/p>\n<p><strong>Retrieving  VID\/PID in application<\/strong><br \/>\nSince it is a  broadcast message, Any running WIN32 application can receive the notification  message in its registered <strong>WinProc<\/strong>. I  have shown the WinProc example for retrieving the VID\/PID in application below.  UINT message \u2013 will receive the device change notification and wParam \u2013 will  receive the\u00a0 current device status  (plugged \/ unplugged) and lparam \u2013 will receive the user defined structure  passed from the USB Host driver.<\/p>\n<ul><em>LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM  wParam, LPARAM lParam)<\/em><br \/>\n<em>{<\/em><br \/>\n<em> int wmId,  wmEvent;<\/em><br \/>\n<em> PAINTSTRUCT ps;<\/em><br \/>\n<em> HDC hdc;<\/em><br \/>\n<em> \u2026\u2026.<\/em><br \/>\n<em> \u2026\u2026.<\/em><br \/>\n<em> \u2026\u2026.<\/em><br \/>\n<em> switch  (message) <\/em><br \/>\n<em> {<\/em><br \/>\n<em> \u2026\u2026.<\/em><br \/>\n<em> \u2026\u2026.<\/em><br \/>\n<em> case  WM_DEVICECHANGE:<\/em><br \/>\n<em> { <\/em><br \/>\n<em>NKDbgPrintfW(L&#8221; Device Change  Notification++\\r\\n&#8221;);<\/em><br \/>\n<em> If(lParam!=NULL)<\/em><br \/>\n<em>userMsg = (DEVICE_VID_PID_INFO*)lParam;<\/em><br \/>\n<em> switch(LOWORD(wParam))<\/em><br \/>\n<em> {<\/em><br \/>\n<em> case DBT_DEVICEREMOVECOMPLETE:<\/em><br \/>\n<em> if(userMsg!=NULL)<\/em><br \/>\n<em> NKDbgPrinftW(L\u201dUSB  Device Unplugged,VID=0x%x,PID=0x%x, IP=0x%x\\r\\n\u201d,\u00a0 userMsg-&gt;dev_vid,userMsg-&gt;dev_pid,  userMsg-&gt;dev_InterfaceProtocol); <\/em><br \/>\n<em> break;<\/em><br \/>\n<em> case DBT_DEVICEARRIVAL:<\/em><br \/>\n<em> if(userMsg!=NULL)<\/em><br \/>\n<em>NKDbgPrinftW(L\u201dUSB Device plugged, VID=0x%x, PID=0x%x,  IP=0x%x\\r\\n\u201d,  userMsg-&gt;dev_vid,userMsg-&gt;dev_pid,  userMsg-&gt;dev_InterfaceProtocol);<\/em><br \/>\n<em> break;<\/em><br \/>\n<em> }<\/em><br \/>\n<em> }<\/em><br \/>\n<em>break;<\/em><br \/>\n<em>\u2026\u2026.<\/em><br \/>\n<em>\u2026\u2026.<\/em><br \/>\n<em>\u2026\u2026.<\/em><br \/>\n<em>}<\/em><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Every windows embedded developer knows that Windows CE is used for customized devices and some&#8230;<\/p>\n","protected":false},"author":12,"featured_media":1389,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[190,192],"tags":[124,126,125,127,132,93],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/posts\/878"}],"collection":[{"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/comments?post=878"}],"version-history":[{"count":19,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/posts\/878\/revisions"}],"predecessor-version":[{"id":1853,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/posts\/878\/revisions\/1853"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/media\/1389"}],"wp:attachment":[{"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/media?parent=878"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/categories?post=878"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.e-consystems.com\/blog\/windowsce\/wp-json\/wp\/v2\/tags?post=878"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}