Process类的CloseMainWindow, Kill, Close

Process.CloseMainWindow是GUI程序的最友好结束方式,从名字上就可以看出来它是通过结束主窗体,相当于用户点击窗体的关闭按钮或者按Alt + F4。它的本质就是向主窗体发送WM_CLOSE消息(Process.MainWindowsHandle可以返回主窗体的句柄)。这个可以在.NET Framework源代码中看出来:

publicbool CloseMainWindow()

{

IntPtr mainWindowHandle =this.MainWindowHandle;

//句柄是否为0

if (mainWindowHandle ==IntPtr.Zero)

{

returnfalse;

}

//GetWindowLong是否成功执行

)

{

returnfalse;

}

//0x10 是 WM_CLOSE消息

//向主窗体发送WM_CLOSE,注意是PostMessage而不是SendMessage

NativeMethods.PostMessage(newHandleRef(this, mainWindowHandle), 0x10, IntPtr.Zero, IntPtr.Zero);

returntrue;

}

CloseMainWindow方法使用PostMessage(不是SendMessage,所以消息会加在消息队列的最后)方法向主窗体发送一个WM_CLOSE消息,这样等主窗体处理完所有消息后,等遇到WM_CLOSE便开始执行退出动作。

比如记事本接到了WM_CLOSE消息但是有未保存的文件记事本会弹出对话框提示用户保存还是不保存还是取消退出操作。Windows Forms和WPF的窗体都会有类似操作,通过窗体的Closing事件来在WM_CLOSE消息接收后做出是否退出的决定。

之后我们会讲到Windows Forms和WPF都有自己的友好型常规退出方式,但是其实有一个通用的GUI程序退出方式,就是利用这个CloseMainWindow方法:

//Windows Forms和WPF都可以用

//Windows Forms的Form.Closing事件会在之后发生

//WPF的Windows.Closing事件也会

Process.GetCurrentProcess().CloseMainWindow();

接下来就是Process.Kill方法,从名字也可以看出来,直接杀掉,不给喘息喘息机会呵呵。Kill方法会直接结束整个进程,不进行常规资源清理(什么finally块等……)。Kill本质调用本地API:TerminateProcess函数。

最后一个是Process.Close方法。抱歉它根本不是用来结束进程的!这个方法名字有些误导,其实根本则不然。它仅仅是而是IDisposable的Dispose方法的具体执行,用来进行Process类的托管资源清理的!

由于Process类继承自Component类,后者继承IDisposable而同时又有析构函数,而通过一个继承类可改写的Dispose方法(参数是bool disposing)来判断这个Dispose是用户调用还是GC调用。而这个Process.Close()方法正是用户调用Dispose时进行托管资源的清理方法:

下面Process.Dispose方法代码:

protectedoverridevoid Dispose(bool disposing)

{

if (!this.disposed)

{

if (disposing)

{

//用户调用,清理托管资源

this.Close();

}

this.disposed =true;

//调用Component的Dispose

base.Dispose(disposing);

}

}

这个Close方法类似很多其他.NET中的类,比如Stream……因此Close肯定不会结束进程,仅仅是Process类作为IDisposable接口的间接继承者的自我清理方法。

Environment类的Exit和FailFast

Environment.Exit相当于在Main函数中的return指令。不过它不会执行代码块的finally块(如果有的话),但资源清理还是要进行的。

它是最常见的退出当前进程的方法之一。在Main函数中我们可以直接return语句便退出了程序。如果不在Main函数内,那么Environment.Exit方法就可以派上用场:

classa

{

~a()

{

Console.WriteLine("析构函数");

}

}

classProgram

{

staticvoid Main()

{

try

{

a oa =newa();

test();

}

finally

{

//这段代码永远不会执行

Console.WriteLine("finally");

}

}

staticvoid test()

{

);

}

}

代码将会输出:

析构函数

看来GC调用了oa的析构函数,但注意finally块没有运行。

Environment.FailFast方法更速度,它甚至不需要向操作系统返回进程退出代码(ExitCode),直接结束当前进程并在应用程序事件薄中写入信息,用于程序出现致命错误需要立即停止。

classa

{

~a()

{

Console.WriteLine("析构函数");

}

}

classProgram

{

staticvoid Main()

{

try

{

a oa =newa();

Environment.FailFast("致命错误发生!");

}

finally

{

//这段代码永远不会执行

Console.WriteLine("finally");

}

}

}

在.NET 4.0下,Environment.FailFast代码会抛出FatalExecutionEngineError,而在4.0之前会抛出ExecutionEngineException。但都不会有任何输出(GC没有清理对象,同时finally块也没有运行)

WPF的Shutdown和Windows Forms的Exit

GUI程序往往都有自己的消息队列和事件管理模式,因此结束一个GUI程序要远复杂与结束一个控制台程序。上述的方法中,Process.Kill和Environment.Exit和FailFast如果用在一个GUI程序中,都会直接强制结束整个程序,而不会激发GUI窗体的一些针对应用程序结束的事件(比如Closing事件)。而上面也讲过:Process.CloseMainWindow通过向主窗体发送一个WM_CLOSE消息可以很好的结束一个GUI程序,不过往往更自然的方法是利用GUI框架本身提供的结束程序的方法。

WPF中是System.Windows.Application.Shutdown方法,它其实就是在当前线程的消息队列Dispatcher对象中加入一个正常优先级(DispatcherPriority.Normal)的回调退出函数,等消息队列最后处理到该项时程序开始退出操作。通常这样使用:

//或者App也可以,WPF程序默认会有一个App类继承Application类

Application.Current.Shutdown();

Windows Forms中是:System.Windows.Forms.Application.Exit方法。它是通过Application.OpenFormsInternal属性先把已经打开的窗体通过正常方式都关闭(运行Form.Closing事件),最后再结束整个应用程序进程。

而且通过WPF的Window.Closing或Windows Forms的Form.Closing事件都可以取消这种形式的退出操作。

非托管的ExitProcess和TerminateProcess

这是Windows API中结束进程的非托管方法。ExitProcess结束进程更友好些,而TerminateProcess会立即强制结束进程。两者的关系有点像Environment.Exit和FailFast,但我不确定本质上是否一样。而且TerminateProcess可以指定进程返回值,但FailFast不可以。两个非托管API的执行都不回运行finally块。

使用起来很简单(关键是P/Invoke,参考:http://www.pinvoke.net,很有用的)

using System.Runtime.InteropServices;

classProgram

{

[DllImport("kernel32.dll")]

staticexternvoid ExitProcess(uint uExitCode);

[DllImport("kernel32.dll", SetLastError =true)]

[return: MarshalAs(UnmanagedType.Bool)]

staticexternbool TerminateProcess(IntPtr hProcess, uint uExitCode);

staticvoid Main()

{

);

//或者

);

}

}

手动发送WM_CLOSE,WM_DESTROY,WM_QUIT消息

在一个GUI程序运行环境下,我们通过得到窗体的句柄,然后便可以向该句柄发送消息,WndProc(Window Procedure)函数会处理相应的事件。其中WM_CLOSE相当于用户点击关闭按钮,使用PostMessage将WM_CLOSE发送至主窗体等价于.NET中Process类的CloseMainWindow方法,当接收到WM_CLOSE消息时,应用程序是可以选择是否真正结束程序的,如果继续结束程序而不取消。接着WM_DESTROY消息会发送,这个消息代表着窗体开始真正关闭,此时可以进行一些资源的清理。最后当前线程接收到WM_QUIT消息,线程的消息循环会被终止。

因此向窗体发送这3个消息,只有WM_CLOSE会引发Closing事件,属于正常窗体退出逻辑,其他两个中消息会直接强行关闭窗体。

注意WM_QUIT消息只能用PostMessage将其送至消息队列尾部,使用SendMessage立即发送在WPF应用程序上运行后程序没有任何反应。

下面是一个WPF程序发送下列消息,(并没有贴XAML,你一定知道怎样加3个按钮然后把Click事件和窗体的Closing事件绑在代码上吧)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//外加命名空间

using System.Diagnostics;

using System.Runtime.InteropServices;

namespace Mgen.TEX

{

publicpartialclassMainWindow : Window

{

public MainWindow()

{

InitializeComponent();

}

//Windows消息值

constuint WM_CLOSE =0x10;

constuint WM_DESTROY =0x02;

constuint WM_QUIT =0x12;

//SendMessage和PostMessage的P/Invoke

[DllImport("user32.dll", CharSet =CharSet.Auto)]

staticexternIntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

[return: MarshalAs(UnmanagedType.Bool)]

[DllImport("user32.dll", SetLastError =true)]

staticexternbool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

//窗体的Closing事件,判断Closing是否被运行

privatevoid Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

{

MessageBox.Show("Closing事件!");

}

//发送三种消息

privatevoid WM_CLOSE_Click(object sender, RoutedEventArgs e)

{

//也可以用PostMessage

SendMessage(Process.GetCurrentProcess().MainWindowHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

}

privatevoid WM_DESTROY_Click(object sender, RoutedEventArgs e)

{

//也可以用PostMessage

SendMessage(Process.GetCurrentProcess().MainWindowHandle, WM_DESTROY, IntPtr.Zero, IntPtr.Zero);

}

privatevoid WM_QUIT_Click(object sender, RoutedEventArgs e)

{

//只能使用PostMessage去将WM_QUIT送至消息队列尾部

PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_QUIT, IntPtr.Zero, IntPtr.Zero);

}

}

}

C#各种结束进程的方法详细介绍的更多相关文章

  1. Android下结束进程的方法

    转自:http://www.cnblogs.com/crazypebble/archive/2011/04/05/2006213.html 最近在做一个类似与任务管理器的东西,里面有个功能,可以通过这 ...

  2. WQL语言简介和WQL测试工具wbemtest.exe使用方法详细介绍

    这篇文章主要介绍了WQL语言简介和WQL测试工具wbemtest.exe使用方法详细介绍,WQL是指Windows管理规范查询语言,需要的朋友可以参考下 WQL就是WMI中的查询语言,WQL的全称是W ...

  3. 04-vi使用方法详细介绍

    vi使用方法详细介绍 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版 ...

  4. PHP之十六个魔术方法详细介绍

    PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用.这里进行详细介绍,感兴趣的小伙伴们可以参考一下. PHP中把以两个下划线__开头 ...

  5. python模块之datetime方法详细介绍

    datetime Python提供了许多内置模块用于操作时间日期,如calendar,time,datetime,这篇文章主要是对datetime进行汇总,datetime模块的借口实现原则更加直观, ...

  6. python模块之calendar方法详细介绍

    calendar,是与日历相关的模块.calendar模块文件里定义了很多类型,主要有Calendar,TextCalendar以及HTMLCalendar类型.其中,Calendar是TextCal ...

  7. Github开源Java项目(Disconf)上传到Maven Central Repository方法详细介绍

    最近我做了一个开源项目 Disconf:Distributed Configuration Management Platform(分布式配置管理平台) ,简单来说,就是为所有业务平台系统管理配置文件 ...

  8. java线程基础巩固---分析Thread的join方法详细介绍,结合一个典型案例

    关于Thread中的join方法貌似在实际多线程编程当中没怎么用过,在当初学j2se的时候倒时去学习过它的用法,不过现在早已经忘得差不多啦,所以对它再复习复习下. 首先先观察下JDK对它的介绍: 其实 ...

  9. iOS—如何申请苹果公司开发者账号流程详细图文介绍(包括邓白氏编码的申请方法详细介绍)

    我们要申请开发者账号,首先就需要先注册一个苹果的apple id,然后再这个账号的基础上去继续,这个相信大家都知道 这是申请appleid的地址:https://appleid.apple.com/a ...

随机推荐

  1. python开发web服务器——搭建简易网站

    参看:https://blog.csdn.net/baidu_35085676/article/details/69807145

  2. gan对抗式网络

    感觉好厉害,由上图噪声,生成左图噪声生成右图以假乱真的图片, gan网络原理: 本弱又盗了一坨博文,不是我写的,如下:(跪膜各路大神) 前面我们已经讲完了一般的深层网络,适用于图像的卷积神经网络,适用 ...

  3. leetcode 之Sum系列(七)

    第一题是Two Sum 同样是用哈希表来做,需要注意的是在查打gap是要排除本身.比如target为4,有一个值为2,gap同样为2. vector<int> twoSum(vector& ...

  4. [重磅]Deep Forest,非神经网络的深度模型,周志华老师最新之作,三十分钟理解!

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 深度学习最大的贡献,个人认为就是表征 ...

  5. csu 1598(KMP)

    1598: 最长公共前缀 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 109  Solved: 92[Submit][Status][Web Boar ...

  6. SQL Server Connection Pooling (ADO.NET)

    SQL Server Connection Pooling (ADO.NET) Connecting to a database server typically consists of severa ...

  7. cordova 使用WKWebView 适配iphoneX及解决不能拨打电话问题

    先安装插件 cordova-plugin-wkwebview-engine 然后修改插件中CDVWKWebViewEngine.m文件,下面是全部代码,修改部分已经进行注释     /* Licens ...

  8. SQL Server 执行计划分析

    当一个查询到达数据库引擎时,SQL Server执行两个主要的步骤来产生期望的查询结果: 第一步:查询编译,生成查询计划. 第二步:执行这个查询计划. 1. 用于演示分析执行计划的查询语句 /* 查询 ...

  9. [Codeforces19D]Points 线段树

    大致题意: 给出n个询问,每次询问有三种: 1.往平面上加一个点 2.删除平面上的一个点 3.给出一个点p,查询平面上某点q,使得q.x>p.x且q.y>p.y,输出x轴坐标最小的q,若有 ...

  10. shell 文件合并,去重,分割

    第一:两个文件的交集,并集前提条件:每个文件中不得有重复行1. 取出两个文件的并集(重复的行只保留一份)2. 取出两个文件的交集(只留下同时存在于两个文件中的文件)3. 删除交集,留下其他的行1. c ...