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

Jim*_*ell 21 c++ usb events asynchronous virtual-serial-port

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

Microsoft网站上的此示例代码显示了如何通过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);
}
Run Code Online (Sandbox Code Playgroud)

PC进入WndProc,但不是在我移除/插入USB设备时.PC似乎永远不会进入OnDeviceChange.任何提示将不胜感激.我需要处理USB设备的意外插入/删除.如果它有所不同,USB设备将显示为Windows的虚拟COM端口.谢谢.

条件信息:CreateWindowEx使用atom返回的类调用RegisterClassEx失败,并显示错误消息"无法找到窗口类".

_hWnd = CreateWindowEx( 0, (LPCTSTR)&atom, pWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
Run Code Online (Sandbox Code Playgroud)

新的方法

我也在尝试这种新方法.我正在尝试编写一个仅用于消息的窗口来接收USB设备的设备更改通知消息.我正在使用MFC,C++和Visual Studio 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.
};
Run Code Online (Sandbox Code Playgroud)

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

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 );
}
Run Code Online (Sandbox Code Playgroud)

任何想法或建议将不胜感激.如果缺少任何细节,请告诉我,我很乐意添加它们.谢谢.

是否只需要在新线程中启动仅消息窗口,或者创建新窗口是否会自动剥离新线程?

kic*_*hik 15

创建一个虚拟窗口,除了等待WM_DEVICECHANGE并使用注册该窗口之外什么也不做RegisterDeviceNotification.恕我直言,WMI在这里是一种矫枉过正.


Ste*_*end 8

在本机代码中有一个专门针对您的案例的MSDN示例.

注册设备通知

这样做比通过WMI更好.


Joh*_*n W 7

我按照你的"新方法",也发现没有调用OnDeviceChange.问题是没有消息循环,因为它是一个控制台应用程序.定期调用以下功能修复它.

void check_for_device_change()
{
    MSG msg; 

    const int val = PeekMessage( &msg, 0, 0, 0, PM_REMOVE );

    if( val > 0 )
    { 
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    } 
}
Run Code Online (Sandbox Code Playgroud)