对于一个非模态子对话框的内存释放,一般的处理方法是在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. ”仿佛是错误的。
view plaincopy to clipboardprint?
01.// 能收到关闭消息
02.void CStaticMultiDlg::OnButtonCreate()
03.{
04. // TODO: Add your control notification handler code here
05. CDialogChild *pDlg = new CDialogChild;
06. pDlg->Create( IDD_DIALOG_CHILD, NULL);
07. pDlg->ShowWindow( SW_SHOW);
08. CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???}
09. CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???}
10.}
11.// 能收到关闭消息
12.void CStaticMultiDlg::OnButtonCreate()
13.{
14. // TODO: Add your control notification handler code here
15. CDialogChild *pDlg = new CDialogChild;
16. pDlg->Create( IDD_DIALOG_CHILD, this);
17. pDlg->ShowWindow( SW_SHOW);
18. CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???}
19. CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???}
20.}
21.
22.// 收不到关闭消息
23.void CStaticMultiDlg::OnButtonCreate()
24.{
25. // TODO: Add your control notification handler code here
26. CDialogChild *pDlg = new CDialogChild;
27. pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow());
28. pDlg->SetParent(GetDesktopWindow());
29. pDlg->ShowWindow( SW_SHOW);
30. CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010}
31. CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???}
32. CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x00000000 {CWnd hWnd=???}
33.}
34.// 收不到关闭消息
35.void CStaticMultiDlg::OnButtonCreate()
36.{
37. // TODO: Add your control notification handler code here
38. CDialogChild *pDlg = new CDialogChild;
39. pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow());
40. pDlg->SetOwner(this);
41. pDlg->ShowWindow( SW_SHOW);
42. CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010}
43. CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???}
44. CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x0012fdf4 {CStaticMultiDlg hWnd=0x001004f2} == this
45.}
46.// 这种情况下程序会假死
47.void CStaticMultiDlg::OnButtonCreate()
48.{
49. // TODO: Add your control notification handler code here
50. CDialogChild *pDlg = new CDialogChild;
51. pDlg->Create( IDD_DIALOG_CHILD, GetDesktopWindow());
52. pDlg->SetParent(this);
53. pDlg->SetOwner(this);
54. pDlg->ShowWindow( SW_SHOW);
55. CWnd *pDes = GetDesktopWindow(); // pDes 0x00373458 {CTempWnd hWnd=0x00010010}
56. CWnd *pParent = pDlg->GetParent(); // pParent 0x00000000 {CWnd hWnd=???}
57. CWnd *pOwner = pDlg->GetOwner(); // pOwner 0x0012fdf4 {CStaticMultiDlg hWnd=0x001004f2} == this
58.}
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/bao_qibiao/archive/2009/08/31/4504647.aspx
delete this这个记得以前在那见过,确实很犀利,可是今天给忘了,尴尬,记下来,以备后患。
OnCancel()与OnOK();都是CDialog的成员函数。
CDialog::OnOK
说明当用户按OK按钮(ID是IDOK)时调用。覆盖该函数执行OK按钮动作。如果对话框包括自动数据检验和交换,缺省方式是对应用的某些变量进行数据的检验和更新。如果在非模态对话框中实现OK按钮,必须覆盖OnOK成员函数,并在其中调用DestoryWindow 。不能调用基类成员函数,那将会调用EndDialog,使对话框虽然存在但不可视。
CDialog::OnCancel
说明当用户在模态对话框或非模态对话框内单击Cancel按钮或按ESC键时,窗体调用这个成员函数。覆盖该成员函数,执行Cancel按钮动作,缺省方式是调用EndDialog来简单中止模态对话框,并使DoModal 返回IDCANCEL。如果在非模态对话框中实现Cancel按钮,必须覆盖OnCancel成员函数,并在其中调用DestoryWindow 。不能调用基类成员函数,那将会调用EndDialog,使对话框虽然存在但不可视。