2010-12-02 4 views
0

Mon application console engendre une nouvelle fenêtre (invisible) dans son propre thread. Avant de quitter l'application, il tente de nettoyer et le dernier appel à GetMessage dans la pompe de message de la fenêtre échoue. GetLastError renvoie 1400, "handle de fenêtre non valide."La fermeture de la fenêtre et du thread génère une erreur de poignée de fenêtre non valide - C++

Voici comment le produit Nettoyons dans le fil d'application:

if (s_hNotifyWindowThread != NULL) 
{ 
    ASSERT(s_pobjNotifyWindow != NULL); 

    ::PostMessage(s_pobjNotifyWindow->m_hWnd, WM_CLOSE, 0, 0); 
    ::WaitForSingleObject(s_hNotifyWindowThread, 50000L);  // Step 1: breakpoint here 
    ::CloseHandle(s_hNotifyWindowThread);      // Step 4: breakpoint here 
    s_hNotifyWindowThread = NULL; 
} 

Ce WndProc existe dans le nouveau thread créé pour la fenêtre:

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (uMsg) 
    { 
    case WM_CLOSE: 
     ::DestroyWindow(hWnd); // Step 2: breakpoint here 
     break; 

    case WM_DESTROY: 
     ::PostQuitMessage(0);  // Step 3: breakpoint here 
     break; 

    case WM_DEVICECHANGE: 
     /* Handle device change. */ 
     break; 

    default: 
     // Do nothing. 
     break; 
    } 

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

Ceci est en fonction de fil de la fenêtre où la nouvelle fenêtre est créée et mon message pompe est situé:

s_pobjNotifyWindow = new CNotifyWindow(pParam); 

while ((bRetVal = ::GetMessage(
    &msg,       // message structure 
    s_pobjNotifyWindow->m_hWnd,  // handle to window whose messages are to be retrieved 
    0,        // lowest message value to retrieve 
    0        // highest message value to retrieve 
    )) != 0) 
{ 
    switch (bRetVal) 
    { 
    case -1:      // Error generated in GetMessage. 
     TRACE(_T("NotifyWindowThreadFn : Failed to get notify window message.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__); 
     return ::GetLastError(); // Step 5: breakpoint here: Returns error 1400 
     break; 

    default:      // Other message received. 
     ::TranslateMessage(&msg); 
     ::DispatchMessage(&msg); 
     break; 
    } 
} 

Qu'est-ce que je fais mal? Merci.

Répondre

5

Vous transmettez un handle de fenêtre non valide à GetMessage, c'est pourquoi il échoue et signale qu'un handle de fenêtre n'est pas valide.

Vous verrez la même erreur si vous exécutez ce code avec une poignée de fenêtre maquillée:

MSG msg = {0}; 
BOOL b = ::GetMessage(&msg, (HWND)(0x123000), 0, 0); 

if (b == -1) 
{ 
    DWORD dwErr = ::GetLastError(); 
    wprintf(L"%lu\n", dwErr); 
} 

Le problème est que vous utilisez toujours la poignée de fenêtre après la fenêtre a été détruite. Dès qu'une fenêtre est détruite, son handle est invalide (ou, pire, réutilisé par une autre fenêtre). La pompe de message ne quittera pas tant qu'elle n'aura pas traité le message quit. Comme le message quit est affiché pendant la destruction de la fenêtre, il sera traité après la destruction de la fenêtre. C'est-à-dire que votre pompe à messages continue à fonctionner pendant une courte période après la destruction de votre fenêtre.

Passez simplement NULL à GetMessage pour l'argument de la fenêtre, afin qu'il récupère les messages pour toutes les fenêtres de ce thread. Comme le thread n'existe que pour cette fenêtre, il ne recevra des messages que pour cette fenêtre. (Plus le message quit posté sur le thread lui-même, et potentiellement les messages pour d'autres fenêtres que des choses comme COM crée si vous utilisez COM sur ce thread ... Vous voudriez certainement traiter ces messages, disant à GetMessage de filtrer par fenêtre ne fait rien au mieux et pourrait empêcher que quelque chose ne fonctionne au pire, en plus de l'erreur que vous voyez renvoyer GetMessage.)

Questions connexes