对于一个非模态子对话框的内存释放,一般的处理方法是在OnClose() 函数中添加DestroyWindow() ,然后在PostNcDestroy() 中delete this 。
当我们为了使得生成的非模态子对话框最小化的时候在任务栏上显示出来,创建的时候就要以桌面为父窗口,如下:
pdlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow() );
这种情况下,如果你先关闭非模态子对话框,再关闭主对话框是没有问题的。但当你关闭主对话框的时候,如果这时还有前面说的非模态子对话框存在,那么就会造成内存泄露。原因是此时pdlg并没有接收到任何关闭的消息。
我们的解决方法是在父窗口中保存一个非模态子对话框的指针pdlgCopy,这个指针在pdlg存在的情况下要赋值,在pdlg销毁的情况下要清零。然后在主对话框关闭的时候检查这个指针,如果不为空,则释放。
现在又有新的问题,如果你在pdlg里面的操作分配了内存,但是你是在pdlg的PostNcDestroy() 中释放的话,那么还是会有内存泄露,因为在父窗口中删除那个非模态对话框指针的时候,只会进pDlg的析构函数,而不进PostNcDestroy()。 所以要么你在析构函数中释放内存,要么你在父窗口中调用pdlgCopy->DestroyWindow()。前者要注意此时this指针和对象句柄都已为NULL,而且你的子控件中的内存释放是否依赖于WM_DESTROY,后者方法要注意你本来DestroyWindow()中就有把pdlgCopy置为NULL的操作,如果对话框指针多了要用模板保存,还要注意迭代器失效的问题。
为什么pdlg接收不到任何关闭的消息?
关于窗口的parent和owner的区别:
下面是MSDN中的解释:
http://support.microsoft.com/default.aspx?scid=kb;en-us;84190
SUMMARY
In the Windows environment, the following two relationships can exist between windows:
Owner-owned relationship. The owner-owned relationship determines which other windows are automatically destroyed when a window is destroyed. When window A is destroyed, Windows automatically destroys all the windows that are owned by A.
Parent-child relationship. The parent-child relationship determines where a window can be drawn on the screen. A child window (that is, a window that has a parent) is confined to its parent window's client area.
This article discusses these relationships and some Windows functions that provide owner and parent information for a specified window.
下面这个例子证明“The owner-owned relationship determines which other windows are automatically destroyed when a window is destroyed. ”仿佛是错误的。
// 能收到关闭消息 void CStaticMultiDlg::OnButtonCreate() { // TODO: Add your control notification handler code here CDialogChild *pDlg = new CDialogChild; pDlg->Create( IDD_DIALOG_CHILD, NULL); pDlg->ShowWindow( SW_SHOW); CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???} CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???} } // 能收到关闭消息 void CStaticMultiDlg::OnButtonCreate() { // TODO: Add your control notification handler code here CDialogChild *pDlg = new CDialogChild; pDlg->Create( IDD_DIALOG_CHILD, this); pDlg->ShowWindow( SW_SHOW); CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???} CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???} } // 收不到关闭消息 void CStaticMultiDlg::OnButtonCreate() { // TODO: Add your control notification handler code here CDialogChild *pDlg = new CDialogChild; pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow()); pDlg->SetParent(GetDesktopWindow()); pDlg->ShowWindow( SW_SHOW); CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010} CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???} CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???} } // 收不到关闭消息 void CStaticMultiDlg::OnButtonCreate() { // TODO: Add your control notification handler code here CDialogChild *pDlg = new CDialogChild; pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow()); pDlg->SetOwner(this); pDlg->ShowWindow( SW_SHOW); CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010} CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???} CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x0012fdf4 {CStaticMultiDlg hWnd=0x001004f2} == this } // 这种情况下程序会假死 void CStaticMultiDlg::OnButtonCreate() { // TODO: Add your control notification handler code here CDialogChild *pDlg = new CDialogChild; pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow()); pDlg->SetParent(this); pDlg->SetOwner(this); pDlg->ShowWindow( SW_SHOW); CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010} CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???} CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x0012fdf4 {CStaticMultiDlg hWnd=0x001004f2} == this }