C++ 关闭窗口和线程会生成无效的窗口句柄错误-C++;

C++ 关闭窗口和线程会生成无效的窗口句柄错误-C++;,c++,multithreading,visual-studio-2008,exception,C++,Multithreading,Visual Studio 2008,Exception,我的控制台应用程序在自己的线程中生成一个新的(不可见的)窗口。退出应用程序之前,它会尝试清理,窗口消息泵中最后一次调用GetMessage失败GetLastError返回1400,“无效的窗口句柄。” 以下是应用程序线程中的清理过程: if ( s_hNotifyWindowThread != NULL ) { ASSERT(s_pobjNotifyWindow != NULL); ::PostMessage( s_pobjNotifyWindow->m_hWnd, WM

我的控制台应用程序在自己的线程中生成一个新的(不可见的)窗口。退出应用程序之前,它会尝试清理,窗口消息泵中最后一次调用
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 );
}
这是在窗口的线程函数中创建的新窗口和my message pump所在的位置:

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

我做错了什么?谢谢。

您正在向GetMessage传递一个无效的窗口句柄,这就是它失败并报告窗口句柄无效的原因

如果使用虚构的窗口句柄运行此代码,您将看到相同的错误:

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

if (b == -1)
{
    DWORD dwErr = ::GetLastError();
    wprintf(L"%lu\n", dwErr);
}
问题是,在窗口被销毁后,您仍在使用窗口句柄。一旦一个窗口被破坏,它的句柄就无效(或者更糟的是,被其他窗口重复使用)。在处理退出消息之前,消息泵不会退出。由于退出消息是在窗口销毁期间发布的,因此将在窗口销毁完成后进行处理。i、 e.在您的窗口被破坏后,您的信息泵会持续运行一小段时间


只需将NULL传递给窗口参数的GetMessage,以便它检索该线程上所有窗口的消息。由于该线程只存在于该窗口中,因此它只会获取该窗口的消息。(加上发布到线程本身的退出消息,以及如果在该线程上使用COM,可能会为COM之类的东西创建的其他窗口的消息……您肯定希望处理这些消息,因此告诉GetMessage按窗口进行筛选充其量是什么也做不到,除了错误之外,还可能阻止某些东西在最坏的情况下工作。)您将看到GetMessage返回。)

您正在向GetMessage传递无效的窗口句柄,这就是它失败并报告窗口句柄无效的原因

如果使用虚构的窗口句柄运行此代码,您将看到相同的错误:

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

if (b == -1)
{
    DWORD dwErr = ::GetLastError();
    wprintf(L"%lu\n", dwErr);
}
问题是,在窗口被销毁后,您仍在使用窗口句柄。一旦一个窗口被破坏,它的句柄就无效(或者更糟的是,被其他窗口重复使用)。在处理退出消息之前,消息泵不会退出。由于退出消息是在窗口销毁期间发布的,因此将在窗口销毁完成后进行处理。i、 e.在您的窗口被破坏后,您的信息泵会持续运行一小段时间

只需将NULL传递给窗口参数的GetMessage,以便它检索该线程上所有窗口的消息。由于该线程只存在于该窗口中,因此它只会获取该窗口的消息。(加上发布到线程本身的退出消息,以及如果在该线程上使用COM,可能会为COM之类的东西创建的其他窗口的消息……您肯定希望处理这些消息,因此告诉GetMessage按窗口进行筛选充其量是什么也做不到,除了错误之外,还可能阻止某些东西在最坏的情况下工作。)您将看到GetMessage返回。)