2010-12-01 98 views
1

我的应用程序创建一个窗口,用于处理WM_DEVICECHANGE Windows消息。 WndProc确实被调用过几次,直到我的应用程序调用一个函数来轮询键盘事件为止,但无论出于何种原因,当我删除或插入USB设备时它都不会被调用。WM_DEVICECHANGE消息未发送到WndProc - C++

这是我的USB设备的GUID。我相信这是正确的:

static const GUID _guidForCP210xDevices = { 
    0xA2A39220, 0x39F4, 0x4B88, 0xAE, 0xCB, 0x3D, 0x86, 0xA3, 0x5D, 0xC7, 0x48 
}; 

这是如何创建我的窗口:

m_hInstance = ::GetModuleHandle(NULL); 

if (m_hInstance == NULL) 
{ 
    TRACE(_T("CNotifyWindow::CNotifyWindow : Failed to retrieve the module handle.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
    THROW(::GetLastError()); 
} 

m_wcx.cbSize = sizeof(WNDCLASSEX); // size of structure 
m_wcx.style = CS_HREDRAW | CS_VREDRAW; // initially minimized 
m_wcx.lpfnWndProc = &WndProc;  // points to window procedure 
m_wcx.cbClsExtra = 0;    // no extra class memory 
m_wcx.cbWndExtra = 0;    // no extra window memory 
m_wcx.hInstance = m_hInstance;  // handle to instance 
m_wcx.hIcon = ::LoadIcon(NULL, IDI_APPLICATION); // default app icon 
m_wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW); // standard arrow cursor 
m_wcx.hbrBackground = NULL;   // no background to paint 
m_wcx.lpszMenuName = NULL;   // no menu resource 
m_wcx.lpszClassName = _pwcWindowClass; // name of window class 
m_wcx.hIconSm = NULL;    // search system resources for sm icon 

m_atom = ::RegisterClassEx(&m_wcx); 

if (m_atom == 0) 
{ 
    TRACE(_T("CNotifyWindow::CNotifyWindow : Failed to register window class.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
    THROW(::GetLastError()); 
} 

m_hWnd = ::CreateWindow(
    _pwcWindowClass, 
    _pwcWindowName, 
    WS_ICONIC, 
    0, 
    0, 
    CW_USEDEFAULT, 
    0, 
    NULL, 
    NULL, 
    m_hInstance, 
    NULL 
    ); 

if (m_hWnd == NULL) 
{ 
    TRACE(_T("CNotifyWindow::CNotifyWindow : Failed to create window.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
    THROW(::GetLastError()); 
} 

::ShowWindow(m_hWnd, SW_HIDE); // function does not fail 

if (RegisterForNotification() != ERROR_SUCCESS) 
{ 
    TRACE(_T("CNotifyWindow::CNotifyWindow : Failed to register for device notification.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
    THROW(::GetLastError()); 
} 

这是我如何注册设备通知:

static DEV_BROADCAST_DEVICEINTERFACE dbt = {0}; 

ASSERT(m_hWnd != NULL); 

// Populate DEV_BROADCAST_DEVICEINTERFACE structure. 
dbt.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); 
dbt.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 
dbt.dbcc_classguid = _guidForCP210xDevices; 

// Register for HID devic notifications 
m_hNotify = RegisterDeviceNotification(m_hWnd, &dbt, DEVICE_NOTIFY_WINDOW_HANDLE); 

if (m_hNotify == NULL) 
{ 
    TRACE(_T("CNotifyWindow::RegisterForNotification : Failed to register for device notification.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
    return ::GetLastError(); 
} 

return ERROR_SUCCESS; 

WndProc功能看起来像这个:

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    DEV_BROADCAST_HDR * pHeader = reinterpret_cast<DEV_BROADCAST_HDR *>(lParam); 

    switch (uMsg) 
    { 
    case WM_DEVICECHANGE: 
     if (pHeader != NULL) 
     { 
      if (pHeader->dbch_devicetype == DBT_DEVTYP_PORT) 
      { 
       OnDeviceChange(wParam); 
      } 
     } 
     break; 

    default: 
     // Do nothing. 
     break; 
    } 

    return ::DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

有谁知道我做错了什么?谢谢。

+0

你说WndProc的作品'直到我的函数轮询键盘事件被称为'。这意味着您正在阻止消息泵处理任何进一步的消息 - 包括您的设备通知。很明显,为了清楚起见,您已经删除了一些代码,因此很难判断这是否是实际问题。 – Jon 2010-12-01 17:21:16

回答

4

您错过了一个消息泵来从队列中检索通知并将其发送到您的WndProc。消息泵实际上是一个循环,用于检查消息并同步调用相应的WndProc。 MSDN有一些关于它们的好信息。我不知道你的代码的上下文是什么,所以我不确定你是否需要在RegisterForNotification之后插入一个泵,或者是否需要更大的体系结构更改。