2010-12-01 45 views
1

Mon application crée une fenêtre dans le but de gérer le message Windows WM_DEVICECHANGE. WndProc est appelée plusieurs fois, jusqu'à ce que mon application appelle une fonction pour interroger les événements clavier, mais pour une raison quelconque, elle n'est pas appelée lorsque je supprime ou insère mon périphérique USB.Les messages WM_DEVICECHANGE ne sont pas envoyés à WndProc - C++

Ceci est le GUID de mon périphérique USB. Je suis sûr qu'il est correct:

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

Voici comment ma fenêtre est créée:

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

Voici comment je me inscrire pour la notification de l'appareil:

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; 

Ma fonction WndProc ressemble ce:

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

Est-ce que quelqu'un sait ce que je fais mal? Merci.

+0

Vous dites que le WndProc fonctionne 'jusqu'à ce que ma fonction d'interrogation des événements clavier soit appelée'. Cela implique que vous empêchez la pompe de messages de traiter d'autres messages - les notifications de votre appareil incluses. Il est assez clair que vous avez excisé du code ici pour plus de clarté, donc il est difficile de dire si c'est le vrai problème. – Jon

+0

Essayez-vous toujours d'exécuter WndProc dans un thread de travail? –

+0

@Jon: Mes excuses, il était censé dire, "... jusqu'à ce que mon application appelle une fonction à interroger pour les événements de clavier." La faute de frappe a été corrigée. En ce qui concerne la pompe de message, qu'est-ce que c'est? Est-ce qu'il fonctionne/appelle 'WndProc' de façon asynchrone? –

Répondre

4

Il vous manque une pompe de message pour récupérer les notifications de la file d'attente et les envoyer à votre WndProc. La pompe de message est effectivement une boucle qui vérifie les messages et appelle le WndProc approprié de manière synchrone. MSDN a de bonnes informations sur eux. Je ne sais pas quel est le contexte de votre code, donc je ne suis pas sûr si vous avez juste besoin d'insérer une pompe après RegisterForNotification ou si un changement architectural plus important est nécessaire.