天天看点

MFC子窗口中退出程序

MFC子窗口中退出程序

在子窗口中退出程序应使用PostQuitMessage(0);函数实现。

函数GetMessage里是使用一个循环不断地检测消息,周止复始的,是不可能出现死亡的,但它会检测到消息WM_QUIT就退出来。那现在问题是谁发送WM_QUIT消息出来呢?这就是PostQuitMessage函数所做的工作。当你点击窗口右上角的关闭时,Windows就会把窗口从系统里删除,这时就会发出消息WM_DESTROY给窗口消息处理函数WindowProc,WindowProc收到这条消息后,最需要做的一件事情就是调用PostQuitMessage发出退出消息,让消息循环结束。

函数PostQuitMessage声明如下:

WINUSERAPI

VOID

WINAPI

PostQuitMessage(

    __in int nExitCode); 

nExitCode是退出标识码,它被放到WM_QUIT消息的参数wParam里。

VC关闭窗口退出 http://www.cnblogs.com/carekee/articles/2006715.html

1、OnOK()或OnCancel()//只对窗口程序有用

2、PostQuitMessage(0);//最常用

3、ExitProcess(0);

4、发送WM_CLOSE消息,如:

     SendMessage(WM_CLOSE,   0,   0);

5、TerminateProcess

6、CDialog.Destroy()

7、exit(0);

8、 void CMainFrame::OnClose()

     {

          // TODO: Add your message handler code here and/or call default

          if (MessageBox("确定要退出吗?","提示",MB_YESNO|MB_DEFBUTTON2)==IDYES)

          {

                 CFrameWnd::OnClose();

          }

     }

如果是关闭其它程序

// 一种方法,通过窗口文字

HWND hWnd = ::FindWindow(NULL, _T("MSDN Library Visual Studio 6.0")); // 注: 这个是窗口的标题文字

 if (NULL != hWnd) {

       ::SendMessage(hWnd, WM_CLOSE, 0, 0);

   }

//另外一种方法,进程ID

DWORD id_num;

HWND hWnd = ::FindWindow(NULL, _T("MSDN Library Visual Studio 6.0"));  

GetWindowThreadProcessId(hWnd, &id_num); //注意:第二个参数是进程的ID,返回值是线程的ID。

HANDLE hd = OpenProcess(PROCESS_ALL_ACCESS,FALSE, id_num);

TerminateProcess(hd, 0);

如果窗口文字是会变的,可以使用FindWindow的第一个参数:应用程序的类名。

可以通过VC提供的Spy++这个软件获得ClassName。

从开始菜单->MS 6.0 Tools->spy++,找出你要关闭的程序,比如说spy++,双击它,看Class选项的Class Name是Afx:400000:8:10011:0:15503db。

然后:

HWND hWnd = ::FindWindow(_T("Afx:400000:8:10011:0:15503db"), NULL);  

GetWindowThreadProcessId(hWnd, &id_num); //注意:第二个参数是进程的ID,返回值是线程的ID。

HANDLE hd = OpenProcess(PROCESS_ALL_ACCESS,FALSE, id_num);

TerminateProcess(hd, 0);

窗口关闭过程http://blog.sina.com.cn/s/blog_48ab47450100lrib.html

——OnOK(),OnCancel(),OnClose(),EndDialog(),DestroyWindow(),OnDestroy(),OnNcDestroy()

   一、对于非模态窗口,必须重载OnCancel函数,在函数中调用DestroyWindows()方法,且不能调用基类的函数。因为基类函数中调用的是 EndDialog()方法。而OnClose()也会调用OnCancel()方法。另外想通过OnOK关闭对话框,也必须同样处理,不能直接用默认方法。

   1 、只有点击标题栏的叉号图标、在桌面任务栏右键-关闭、Alt+F4、标题栏最左边图标上单击-关闭,发送WM_CLOSE消息,触发 OnClose()。

 所以对于非模态窗口,其关闭过程

OnClose()->OnCancel()->DestroyWindow()->OnDestroy()->OnNcDestroy() ,                 ->仅表示时间先后而已

而OnNcDestroy()最后又调用了PostNcDestroy()

  2、回车、ESC、点击“确定”或“取消”,都不会调用OnClose()

  一般来说,OnOK是对ID_OK的响应, OnCancel是对IDCANCEL的响应. 前者对应键盘的Enter, 后者对应Esc。

  OnCancel()->DestroyWindow()->OnDestroy()->OnNcDestroy()

  OnOK()->DestroyWindow()->OnDestroy()->OnNcDestroy()

  OnNcDestroy()最后又调用了PostNcDestroy()

  OnOK()与OnCancel()

       如前面所述,OnOK是对ID_OK的响应, OnCancel是对IDCANCEL的响应. 前者对应键盘的Enter, 后者对应Esc。

  OnOK()和OnCancel()都调用了EndDialog().OnOK调用了UpdateData(TRUE)而OnCacel()没有调用。

  在OnOK()结束刚进入DestroyWindow时,其实窗口并未关闭,依然可以用ShowWindow显示出来

  模态的对话框可以用EndDialog来销毁, 非模态的对话框要用DestroyWindow来销毁

  见《OnOK与OnCancel》http://ponymaggie.blog.sohu.com/135823530.html

  EndDialog()

  该函数清除一个模态对话框,并使系统中止对对话框的任何处理

  对于DoModal出来的窗口,可以使用默认的OnOk()和OnCancel()来处理。其基类方法中会调用EndDialog()方法。

  它只能在对话框的消息处理函数里使用,并且这个函数调用之后,没有立即就删除对话框的,而是设置了操作系统里的结束标志。当操作系统查检到有这个标志时,就去删除对话框的消息循环,同时也去释放对话框占用的资源。其实对话框的生命周期是这样的,先由函数DialogBox创建对话框,这样函数 DialogBox完成创建对话框但还没有显示前会发出消息WM_INITDIALOG,让对话框有机会初始化上面所有窗口或控件的显示,比如设置文本框的字符串等。最后当用户点出确定或者取消的按钮,就收到两个命令IDOK或IDCANCEL,这时就可以调用函数EndDialog来结束对话框的生命。

见《Windows API一日一练(18)EndDialog函数》http://blog.csdn.net/caimouse/archive/2007/07/30/1716140.aspx

  DestroyWindows()

  CWnd::DestroyWindow销毁m_hWnd(必须非空),同时销毁其菜单、定时器,以及完成其他清理工作。

  ::DestroyWindow使将被销毁的窗口失去激活、失去输入焦点,并发送WM_DESTROY、WM_NCDESTROY消息到该窗口及其各级子窗口。如果被销毁的窗口是子窗口且没有设置WM_NOPARENTNOTFIY风格,则给其父窗口发送WM_PARENTNOFITY消息。

  CWnd::OnDestroy()  和 CWnd::OnNcDestroy() 以及 CWnd::PostNcDestroy()

  CWnd::OnDestroy()  调用缺省处理函数Default()。

  CWnd::OnNcDestroy() 首先判断当前线程的主窗口是否是该窗口,如果是且模块非DLL,则发送WM_QUIT消息,使得程序结束;

然后,判断当前线程的活动窗口是否是该窗口,如果是则设置活动窗口为NULL;

     接着,清理Tooltip窗口,调用Default由 Windows缺省处理WM_NCDESTROY消息,UNSUBCLASS,把窗口句柄和MFC

窗口对象分离(Detach);

    最后,调用虚函数PostNcDestoy()。

    见《MFC教程_应用程序的退出》http://www.vczx.com/tutorial/mfc/mfc6.php

    总结一下的话,DestroyWindows可以理解成是主动的,OnDestroy是被动的.  

    用户主动调用DestroyWindows来关闭窗口,而当窗口被关闭时OnDestroy函数被调用!  

    你调用DestroyWindow(),那么系统就会发一个WM_DESTROY的消息,这个消息会调用OnDestroy()函数.

    DestroyWindow()     ------>   WM_DESTROY + WM_NCDESTROY   ------>OnDestroy()   

                                         发消息                                                               响应消息映射

   另外,如果要在退出时提示用户,应在 OnClose()或OnOK()、OnCancel()中作出处理,而不能在响应WM_DESTROY时处理

,因为那是窗口已经销毁了(但应用程序并没有退出)。在处理WM_DESTROY消息时,系统会调用

 PostQuitMessage()向消息队里投递WM_QUIT消息,结束消息循环。(见《VC++深入详解》P18)

   最后注意一个问题,通常我们创建一个非模态窗口时,可能会这样写

{

   CDialog * pWnd = new CMyDialog();

   pWnd->Create(……);

   pWnd->ShowWindow(SW_SHOW);

}

   很肯能是在一个模块或者一个函数中创建窗口,但是却无法知道什么时候关闭窗口。而pWnd也只是作为一个局部变量。那么如何对它进行析构呢?

通常这样是重载虚函数PostNcDestroy()来实现

void CMyDialog::PostNcDestroy()

{

       CDialog::PostNcDestroy();

       delete this;

}

 为什么把对话框类的delete this放在PostNcDestroy中而不是OnNcDestroy?

   这是因为OnNcDestroy只被已建立的窗口调用。如果建立窗口失败(如PreCreateWindow), 则没有窗口处来发送

WM_NCDESTROY消息。PostNcDestroy是在对象窗口被完全删除, 在OnNcDestroy后,甚至在窗口建立失败之后

调用的。

    以上是学习MFC窗口关闭销毁等相关知识时的一些总结。

继续阅读