总结:我们要使用代码关闭程序的话,应该向窗口发送WM_CLOSE或者直接调DestroyWindow(HWND)函数 (默认情况下WM_CLOSE的消息响应就是调用DestroyWindow(HWND) 函数,所以我们直接调用也达到一样的效果).这样可以令操作系统回收窗口占用着的内存资源后再退出程序. 千万不要直接用PostMessage(WM_QUIT);令程序退出,这样程序是可以退出了,但是窗口占用的内存资源就没办法回收,久而久之程序就运行出错了. ------------------------------------------------------------------------------------------------------- 使用PostMessage(WM_QUIT)退出程序时导致的内存泄漏! |
我最近在程序开发中发现我的一个程序运行一段时间以后,就会导致系统崩溃,初步分析以后,得出得结论是有内存泄漏。
经使用NuMega BoundsChecker分析以后发现都是一些系统文件中动态分配的内存模块没有被释放,由于这些new都在VC调用的系统文件中无法用调试的方法更正。于是我生成了一个我的程序的MFC外壳,后台的消息处理一条也不处理。检查发现还是有内存泄漏。我的程序外壳是单文档的,VIEW类是从CFormView继承来的,BoundsChecker分析结果如下:
一次偶然的机会我发现我的一些错误的产生被BoundsChecker指向了
IMPLEMENT_DYNCREATE(CTest1View, CFormView)
即VC中的动态生成宏。既内存的泄漏与MFC的基类中的NEW有关,
由此我在视类的虚析构函数中设置了断点,调试发现果然程序退出时没有执行到
视类的析构函数,当然就会发生内存泄露了,进一步分析发现:原来我在程序中
为了在退出时显示一个与splash screen类似的窗口,而重载了退出函数,
void CTest1View::OnAppExit()
{
//闪现splash screen窗口...........
AfxGetMainWnd()->PostMessage(WM_QUIT);
}
最后使用了向窗口发送退出消息的方法来退出程序,这种方式绕过了一些
窗口的退出时的析构处理,导致了程序的出错。
由此可见,我们在编程的时候一些看似正确,编译运行通过的程序也可能
有一些隐藏的BUG,我的程序也是在长时间不间断的运行中才发现的问题,
而一些不长时间运行的程序,就有可能忽略了这样的问题。
-----再转另外一篇文章
发送WM_QUIT消息可以让Window程序关闭,但经测试用下面程序却无法达到目的:
CWnd *pWnd = CWnd::FindWindow(NULL, “My Window”);
HWND hWnd = pWnd->GetSafeHwnd();
SendMessage(hWnd, WM_QUIT, 0, 0);
而经过尝试,发现用PostMessage却可以:
PostMessage(hWnd, WM_QUIT, 0, 0);
不知道原因,当然要查MSDN了,看一下MSDN的介绍:
The SendMessage function sends the specified message to a window or windows. It calls the window procedure for the specified window and does not return until the window procedure has processed the message.
The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.
从MSDN的解释上看,感觉SendMessage比PostMessage更加安全,因为,SendMessage要等到窗体消息处理完才返回,而PostMessage发送消息后就立即返回,这更令人茫然。既然从这上面看不出SendMessage无法实现的原因,那么就从消息WM_QUIT上查。
The WM_QUIT message indicates a request to terminate an application and is generated when the application calls thePostQuitMessage function. It causes the GetMessage function to return zero.
当应用程序调用PostQuitMessage函数的时候, WM_QUIT消息终止一个程序的,它促使GetMessage函数返回0。
可这里根本就没提SendMessage无法完成终止程序的原因。但在Remark中,却有这样一句:
Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage。至于为什么,就得看PostQuitMessage做什么事了。现在不讨论为什么不让使用PostMessage发送WM_QUIT消息,但就为什么SendMessage无法完成PostMessage能完成的功能来做一下研究。
注意到WM_QUIT消息让消息循环终止归根结底是让GetMessage返回为0,而GetMessage函数是从消息对列里取一条消息,然后再返回,只能当消息为WM_QUIT时才返回0结束消息循环。再仔细看一下SendMessage的注释发现,SendMessage直接发送到窗口,并调用窗口处理程序,完成消息响应,即SendMessage 根本就没有将消息发到消息对列中,因此GetMessage无法从消息对列中收到WM_QUIT的消息。而PostMessage却直接发送消息到消息对列中,然后立即返回,这一点点的区别就解决了我们上面的问题。
了解了这一点,就不难理解上面注释中说的为什么不让直接使用PostMessage来发送WM_QUIT消息来终止程序了。
另外需要注意的是,发送消息让对话框关闭,应该发送WM_CLOSE或者直接调用)消息,这样可以让对话框完成它自身的资源释放回收。