问题概览
近期在完成一个连接多台相机,并实时显示每一个相机窗口的程序过程中,在程序的最后会涉及对显示窗口的关闭。但是期间尝试采用DestroyWindow 和SendMessage 来关闭时都出现了无法关闭或异常中断的问题。详细问题如下
- 在主线程中使用
DestroyWindow 无法关闭生成的子视窗,返回值为false; - 在主线程中使用
SendMessage(g_hwnd[i], WM_CLOSE, 0, 0) 依次关闭多个视窗时,异常中断。
一.DestroyWindow 无法关闭视窗问题
1.问题现象
在主线程中使用DestroyWindow(hwnd) 时无法关闭销毁视窗,该函数返回值为false
bool flag = DestroyWindow(g_hwnd[0]);
2.排查思路
由于该函数并不会返回报错码,故采用GetLastError() 来查看实际的错误原因。将上述代码修改为如下后,再通过断点调试查到的错误码即可获取实际的错误原因。
bool flag = DestroyWindow(g_hwnd[0]);
DWORD err = GetLastError();
3.问题原因及解决办法
通过查看错误对照码,可以看到错误码5对应的是“拒绝访问”,这意味着造成该问题的原因很有可能是所操作的对象权限不够导致,该判断的论据可参考在子线程用调用::DestroyWindow无效,GetlastError为5—拒绝访问。
由于我的程序窗口对象的创建是在其他线程中创建的,而我从主线程对其他线程创建的窗口对象进行销毁的时候,自然就会产生“拒绝访问,无法销毁”这样的问题了。
解决办法:
- 将窗口对象的创建从其他线程移至该线程中来进行。
- 通过给窗口发关闭消息来关闭窗口,窗口消息函数书写如下:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
hWnd = NULL;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
二.用SendMessage 关闭多个视窗时,异常中断
1.问题现象
为处理上一个问题,我决定采用给窗口发消息的方式来关闭窗口,但是采用SendMessage(g_hwnd[i], WM_CLOSE, 0, 0) 来依次关闭多个窗口时,程序总是会异常中断。中断的报错信息基本形式长这样:
0x00007FFADC4A547C (msctf.dll)处(位于 test.exe 中)引发的异常: 0xC0000005
2.排查思路
为解决这一问题,我采用过将轮询方式改为单独销毁,或者在两次发消息期间加等待时间(最大2s),均没有效果,但是发现只发送单窗口的时候并不会中断。从这篇向窗口发送消息SendMessage帖子中受到启发,怀疑还是消息阻塞导致的问题。
3.问题原因及解决办法
问题原因: SendMessage 这个函数发送消息会等待窗口程序处理完消息再返回,如果是给多个窗口发消息,那很有可能造成消息的阻塞。(但我加了等待时间还是没用这点,希望有大佬可以指导说明)
SendMessageW或SendMessageA,这两个函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而和函数PostMessage不同,PostMessage是将一个消息寄送到一个线程的消息队列后就立即返回
解决办法: 采用PostMessage 来发送关闭窗口的消息即可。
PostMessage(g_hwnd[i], WM_CLOSE, 0, 0);
参考引用
- C++ :用GetLastError()查找错误原因;
- 在子线程用调用::DestroyWindow无效,GetlastError为5—拒绝访问
- 向窗口发送消息SendMessage
|