C#各种结束进程的⽅法详细介绍
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是否成功执⾏
if ((NativeMethods.GetWindowLong(new HandleRef(this, mainWindowHandle), -16) &0x8000000) !=0)
{
returnfalse;
}
//0x10 是 WM_CLOSE消息
//向主窗体发送WM_CLOSE,注意是PostMessage⽽不是SendMessage
NativeMethods.PostMessage(new HandleRef(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⽅法就可以派上⽤场:
class a
{
}
}
class Program
{
staticvoid Main()
{
try
{
a oa =new a();
test();
}
finally
{
//这段代码永远不会执⾏
Console.WriteLine("finally");
}
}
staticvoid test()
{
Environment.Exit(0);
}
}
代码将会输出:
析构函数
看来GC调⽤了oa的析构函数,但注意finally块没有运⾏。
Environment.FailFast⽅法更速度,它甚⾄不需要向操作系统返回进程退出代码(ExitCode),直接结束当前进程并在应⽤程序事件薄中写⼊信息,⽤于程序出现致命错误需要⽴即停⽌。
class a
{
}
}
class Program
{
staticvoid Main()
{
try
{
a oa =new a();
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,参考:,很有⽤的)
using System.Runtime.InteropServices;
class Program
{
[DllImport("kernel32.dll")]
staticexternvoid ExitProcess(uint uExitCode);
[DllImport("kernel32.dll", SetLastError =true)]
[return: MarshalAs(UnmanagedType.Bool)]
staticexternbool TerminateProcess(IntPtr hProcess, uint uExitCode);
staticvoid Main()
{
ExitProcess(1);
//或者
TerminateProcess(Process.GetCurrentProcess().Handle, 1);
}
}
⼿动发送WM_CLOSE,WM_DESTROY,WM_QUIT消息
在⼀个GUI程序运⾏环境下,我们通过得到窗体的句柄,然后便可以向该句柄发送消息,WndProc(Window Procedure)函数会处理相应

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。