代码之家  ›  专栏  ›  技术社区  ›  Jim Fell

用C++检测Windows中的USB插入/删除事件

  •  20
  • Jim Fell  · 技术社区  · 14 年前

    我正在为一个现有的应用程序扩展一个扩展,它需要处理USB插入/删除事件。我知道感兴趣的设备的VID/PID。但是,我无法访问窗口句柄,所以我不知道 RegisterDeviceNotification 会很有用,除非有办法通过 WINAPI . 用C++检测USB插入/删除事件的最佳方法是什么?

    This sample code on the Microsoft website 显示如何通过WMI接收事件通知:

    如何修改它以接收USB插入/删除事件?或者,我还有别的办法吗?我正在使用Visual Studio 2008。谢谢。

    附加信息

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

    电脑进入 WndProc ,但在卸下/插入USB设备时不会。这台电脑似乎永远也进不去 OnDeviceChange

    其他信息: 打电话 CreateWindowEx atom 返回者 RegisterClassEx 失败,错误消息为“找不到窗口类”

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

    我也在尝试这种新方法。我正在尝试使用“只写消息”窗口接收USB设备的设备更改通知消息。我使用的是MFC、C++和VisualStudio 2008。所有东西都会编译,运行时不会崩溃或锁定,但事件处理程序永远不会被触发。感兴趣的设备作为虚拟COM端口安装在Windows上。

    我的主应用程序实例化下面描述的类,然后使用while循环等待来自键盘轮询的字符输入。正是在这段等待时间内,我移除并插入USB设备,期望事件被触发。

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

    为了简单起见,我删除了所有清理和错误处理:

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

    如有任何想法或建议,将不胜感激。如果有任何细节遗漏,请告诉我,我很乐意补充。谢谢。

    3 回复  |  直到 14 年前
        1
  •  15
  •   kichik    14 年前

    创建一个只做等待的虚拟窗口 WM_DEVICECHANGE RegisterDeviceNotification . WMI在这里是一个过度杀戮,IMHO。

        2
  •  8
  •   Steve Townsend    14 年前

    MSDN sample 专门针对您的情况,在本机代码中。

    注册设备通知

        3
  •  7
  •   John W    13 年前

    我遵循了你的“新方法”,也发现Ondevichange没有被调用。问题是没有消息循环,因为它是一个控制台应用程序。定期调用下面的函数修复了这个问题。

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