gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-27 22:29:41 27 4
gpt4 key购买 nike

我的控制台应用程序在它自己的线程中生成了一个新的(不可见的)窗口。在退出应用程序之前,它会尝试清理,最后一次调用窗口消息泵中的 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;
}
}

我做错了什么?谢谢。

最佳答案

您将无效的窗口句柄传递给 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 作为 window 参数,以便它检索该线程上所有窗口的消息。由于该线程仅存在于那个窗口,因此无论如何它只会获取该窗口的消息。 (加上发布到线程本身的退出消息,以及如果您在该线程上使用 COM,COM 之类的东西创建的其他窗口的潜在消息......您肯定想要处理这些消息,所以告诉 GetMessage 按窗口过滤除了您看到 GetMessage 返回的错误之外,充其量什么也不做,最坏的情况下可能会阻止某些事情的工作。)

关于c++ - 关闭窗口和线程生成无效的窗口句柄错误 - C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4340779/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com