Закрытие окна и поток генерирует неверную ошибку дескриптора окна - C ++ - PullRequest
0 голосов
/ 03 декабря 2010

Мое консольное приложение порождает новое (невидимое) окно в своем собственном потоке. Перед выходом из приложения оно пытается очиститься, и последний вызов GetMessage в окне сообщений насоса не выполняется. GetLastError возвращает 1400, «Недопустимый дескриптор окна.»

Вот как происходит очистка в потоке приложения:

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

Это WndProc существует в новой теме, созданной для окна:

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

Это функция потока окна, в которой создается новое окно и находится мой насос сообщений:

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

Что я делаю не так? Спасибо.

1 Ответ

5 голосов
/ 03 декабря 2010

Вы передаете недопустимый дескриптор окна в GetMessage, поэтому он не работает и сообщает, что дескриптор окна недопустим.

Вы увидите ту же ошибку, если запустите этот код с обработанным дескриптором окна:

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

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

Проблема в том, что вы все еще используете дескриптор окна после того, как окно было уничтожено. Как только окно разрушено, его дескриптор становится недействительным (или, что еще хуже, используется другим окном). Насос сообщений не выйдет, пока не обработает сообщение о выходе. Поскольку сообщение о выходе отправляется во время уничтожения окна, оно будет обработано после завершения уничтожения окна . т. е. насос сообщений продолжает работать в течение короткого времени после разрушения окна.

Просто передайте NULL в GetMessage в качестве аргумента окна, чтобы он извлекал сообщения для всех окон в этом потоке. Поскольку поток существует только для этого одного окна, он все равно будет получать сообщения только для этого окна. (Плюс сообщение о выходе, опубликованное в самом потоке, и, возможно, сообщения для других окон, которые создает, например, COM, если вы используете COM в этом потоке ... Вы определенно захотите обработать эти сообщения, так что GetMessage отфильтровывает по окнам. ничего не делает в лучшем случае и может помешать что-то работать в худшем случае, в дополнение к ошибке, которую вы видите, возвращает GetMessage.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...