Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting USB Insertion / Removal Events in Windows using C++

Tags:

I am writing an extension for an existing application that needs to handle USB insertion/removal events. I know the VID/PID of the device of interest. However, I don't have access to the window handle, so I don't know if RegisterDeviceNotification will be of much use, unless there is a way to obtain the handle via the WINAPI. What would be the best way to detect USB insertion/removal events with C++?

This sample code on the Microsoft website shows how to receive event notifications via WMI:

How could it be modified to receive USB insertion/removal events? Or, is there another way I should be going about this? I am using Visual Studio 2008. Thanks.

ADDITIONAL INFO

This is what I have so far (minus error-handling):

DEFINE_GUID(GUID_INTERFACE_CP210x, 0x993f7832, 0x6e2d, 0x4a0f, 0xb2, 0x72, 0xe2, 0xc7, 0x8e, 0x74, 0xf9, 0x3e);  MyClass::MyClass() {     // Generate message-only window     _pWndClassEx = (WNDCLASSEX *)malloc( sizeof(WNDCLASSEX) );     memset( _pWndClassEx, 0, sizeof(WNDCLASSEX) );     _pWndClassEx->cbSize = sizeof(WNDCLASSEX);     _pWndClassEx->lpfnWndProc = (WNDPROC)WndProc; // function which will handle messages     _pWndClassEx->hInstance = GetCurrentModule();     _pWndClassEx->lpszClassName = pClassName;     atom = RegisterClassEx( _pWndClassEx );     _hWnd = CreateWindowEx( 0, pClassName, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );      // Register the USB device for notification     _pDevIF = (DEV_BROADCAST_DEVICEINTERFACE *)malloc( sizeof(DEV_BROADCAST_DEVICEINTERFACE) );     memset( _pDevIF, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE) );     _pDevIF->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);     _pDevIF->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;     _pDevIF->dbcc_classguid = GUID_INTERFACE_CP210x;     _hNotifyDevNode = RegisterDeviceNotification( _hWnd, _pDevIF, DEVICE_NOTIFY_WINDOW_HANDLE ); }  static bool OnDeviceChange(UINT nEventType, DWORD dwData) {     switch ( nEventType )     {     case DBT_DEVICEARRIVAL:         // A device has been inserted adn is now available.         break;      case DBT_DEVICEREMOVECOMPLETE:         // Device has been removed.         break;      default:         break;     }      return true; }  static LRESULT WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) {     switch ( message )     {     case WM_DEVICECHANGE:         OnDeviceChange( wParam, lParam ); // Set breakpoint (never gets here)         break;      default:         break;     }      return DefWindowProc(hwnd, message, wParam, lParam); } 

The PC gets into WndProc, but not when I remove/insert my USB device. The PC never seems to get into OnDeviceChange. Any tips would be appreciated. I need to handle unexpected insertions/removals of the USB device. If it makes a difference, the USB device appears as a virtual COM port to Windows. Thanks.

Aditional info: Calling CreateWindowEx using the class atom returned by RegisterClassEx fails with the error message, "Cannot find window class."

_hWnd = CreateWindowEx( 0, (LPCTSTR)&atom, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL ); 

NEW APPROACH

I'm also trying this new approach. I'm trying to get write a message-only window to receive device change notification messages for a USB device. I am using MFC, C++, and Visual Studio 2008. Everything compiles, and it runs without crashing or locking up, but the event handler is never triggered. The device of interest is installed on Windows as a virtual COM port.

My main application instantiates the class described below then waits for a character input from the keyboard polling using a while loop. It is during this wait time that I remove and insert my USB device expecting the event to get fired.

class CMessageOnlyWindow : public CWnd {     DECLARE_DYNAMIC(CMessageOnlyWindow) private:     DEV_BROADCAST_DEVICEINTERFACE * _pDevIF; // The notification filter.     HDEVNOTIFY _hNotifyDev;             // The device notification handle. public:     CMessageOnlyWindow();     virtual ~CMessageOnlyWindow(); protected:     afx_msg BOOL OnDeviceChange( UINT nEventType, DWORD dwData ); private:     void RegisterNotification( void );     void UnregisterNotification( void ); protected:     DECLARE_MESSAGE_MAP()               // Must be last. }; 

For simplicity, I've removed all the cleanup and error-handling:

DEFINE_GUID(GUID_INTERFACE_CP210x, 0x993f7832, 0x6e2d, 0x4a0f, \     0xb2, 0x72, 0xe2, 0xc7, 0x8e, 0x74, 0xf9, 0x3e);  IMPLEMENT_DYNAMIC(CMessageOnlyWindow, CWnd)  CMessageOnlyWindow::CMessageOnlyWindow() {     CString cstrWndClassName = ::AfxRegisterWndClass( NULL );     BOOL bCreated = this->CreateEx( 0, cstrWndClassName,         L"CMessageOnlyWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, 0 );     this->RegisterNotification(); }  CMessageOnlyWindow::~CMessageOnlyWindow() {}  BEGIN_MESSAGE_MAP(CMessageOnlyWindow, CWnd)     ON_WM_DEVICECHANGE() END_MESSAGE_MAP()  afx_msg BOOL CMessageOnlyWindow::OnDeviceChange( UINT nEventType, DWORD dwData ) {     switch ( nEventType ) // <-- Never gets here.     {     case DBT_DEVICEARRIVAL:         break;      case DBT_DEVICEREMOVECOMPLETE:         break;      default:         break;     }      return TRUE; }  void CMessageOnlyWindow::RegisterNotification(void) {     _pDevIF = (DEV_BROADCAST_DEVICEINTERFACE *)malloc( sizeof(DEV_BROADCAST_DEVICEINTERFACE) );     memset( _pDevIF, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE) );     _pDevIF->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);     _pDevIF->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;     _pDevIF->dbcc_classguid = GUID_INTERFACE_CP210x;     _hNotifyDev = RegisterDeviceNotification( this->m_hWnd, _pDevIF, DEVICE_NOTIFY_WINDOW_HANDLE ); }  void CMessageOnlyWindow::UnregisterNotification(void) {     UnregisterDeviceNotification( _hNotifyDev ); } 

Any thoughts or suggestions would be much appreciated. If any details are missing, let me know, and I will be glad to add them. Thanks.

Does the message-only window need to be started in a new thread, or does creating a new window automatically spin off a new thread?

like image 698
Jim Fell Avatar asked Nov 02 '10 14:11

Jim Fell


People also ask

How do I find my USB history on my computer?

If you don't know the name of your computer, go to Settings > System > About. Your computer name is shown at the top. Click the Start button to see the USB history. You can then expand the results to see details such as the time and date it was last used.

How do I remove a USB device that is connected?

Windows: Open the My Computer, Computer, This PC, or Windows Explorer utility. Then right-click the name of your USB device (listed as a removable disk) and select Eject. Mac: Drag the removable disk icon for your USB device from the desktop into the trash.


2 Answers

Create a dummy window that does nothing but wait for WM_DEVICECHANGE and register that window using RegisterDeviceNotification. WMI is an overkill here, IMHO.

like image 70
kichik Avatar answered Nov 17 '22 01:11

kichik


There is a MSDN sample specifically for your case, in native code.

Registering for Device Notification

Better to do it this way than via WMI.

like image 36
Steve Townsend Avatar answered Nov 17 '22 01:11

Steve Townsend