c++ events asynchronous usb virtual-serial-port

Detección de eventos de inserción/eliminación de USB en Windows usando C++



events asynchronous (3)

Estoy escribiendo una extensión para una aplicación existente que necesita manejar eventos de inserción / eliminación de USB. Conozco el VID / PID del dispositivo de interés. Sin embargo, no tengo acceso al identificador de ventana, así que no sé si RegisterDeviceNotification será de mucha utilidad, a menos que haya una forma de obtener el manejador a través de WINAPI . ¿Cuál sería la mejor forma de detectar eventos de inserción / eliminación de USB con C ++?

Este código de muestra en el sitio web de Microsoft muestra cómo recibir notificaciones de eventos a través de WMI:

¿Cómo podría modificarse para recibir eventos de inserción / eliminación de USB? O, ¿hay otra manera en que debería estar yendo sobre esto? Estoy usando Visual Studio 2008. Gracias.

INFORMACIÓN ADICIONAL

Esto es lo que tengo hasta ahora (menos manejo de errores):

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); }

La PC entra en WndProc , pero no cuando WndProc / inserto mi dispositivo USB. La PC nunca parece entrar en OnDeviceChange . Cualquier consejo sería apreciado. Necesito manejar inserciones / remociones inesperadas del dispositivo USB. Si hace una diferencia, el dispositivo USB aparece como un puerto COM virtual para Windows. Gracias.

Información adicional: la llamada a CreateWindowEx utilizando el atom clase devuelto por RegisterClassEx falla con el mensaje de error "No se puede encontrar la clase de ventana".

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

NUEVO ENFOQUE

También estoy probando este nuevo enfoque. Estoy intentando escribir una ventana de solo mensaje para recibir mensajes de notificación de cambio de dispositivo para un dispositivo USB. Estoy usando MFC, C ++ y Visual Studio 2008. Todo se compila y se ejecuta sin bloquearse o bloquearse, pero el controlador de eventos nunca se desencadena. El dispositivo de interés está instalado en Windows como un puerto COM virtual.

Mi aplicación principal ejemplifica la clase descrita a continuación y luego espera una entrada de caracteres desde el sondeo del teclado mediante un ciclo while. Es durante este tiempo de espera que elimino e inserto mi dispositivo USB esperando que el evento sea despedido.

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. };

Para simplificar, eliminé toda la limpieza y el manejo de errores:

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 ); }

Cualquier idea o sugerencia sería muy apreciada. Si falta algún detalle, házmelo saber y estaré encantado de agregarlo. Gracias.

¿La ventana de solo mensaje debe iniciarse en un nuevo hilo o la creación de una nueva ventana deriva automáticamente un nuevo hilo?


Cree una ventana ficticia que no haga más que esperar a WM_DEVICECHANGE y registrar esa ventana usando RegisterDeviceNotification . WMI es una exageración aquí, en mi humilde opinión.


Hay una muestra de MSDN específicamente para su caso, en código nativo.

Registrarse para la notificación del dispositivo

Mejor hacerlo de esta manera que a través de WMI.


Seguí tu "nuevo enfoque" y también descubrí que no se llamaba a OnDeviceChange. El problema era que no había ningún bucle de mensajes porque era una aplicación de consola. Llamar a la siguiente función a intervalos regulares lo solucionó.

void check_for_device_change() { MSG msg; const int val = PeekMessage( &msg, 0, 0, 0, PM_REMOVE ); if( val > 0 ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } }