C#中各种结束进程的方法

 

Process类的CloseMainWindow, Kill, Close:

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

public bool CloseMainWindow()

{

IntPtr mainWindowHandle = this.MainWindowHandle;

//句柄是否为0

if (mainWindowHandle == IntPtr.Zero)

{

return false;

}

//GetWindowLong是否成功执行

if ((NativeMethods.GetWindowLong(new HandleRef(this, mainWindowHandle), -16) &0x8000000) != 0)

{

return false;

}

//0x10 是 WM_CLOSE消息

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

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

return true;

}

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();

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

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

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

下面Process.Dispose方法代码:

protected override void Dispose(bool disposing)

{

if (!this.disposed)

{

if (disposing)

{

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

this.Close();

}

this.disposed = true;

//调用Component的Dispose

base.Dispose(disposing);

}

}

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

Environment类的Exit和FailFast

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

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

class a

{

~a()

{

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

}

}

class Program

{

static void Main()

{

try

{

a oa = new a();

test();

}

finally

{

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

Console.WriteLine("finally");

}

}

static void test()

{

Environment.Exit(0);

}

}

代码将会输出:

析构函数

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

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

class a

{

~a()

{

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

}

}

class Program

{

static void 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,参考:http://www.pinvoke.net,很有用的)

using System.Runtime.InteropServices;

class Program

{

[DllImport("kernel32.dll")]

static extern void ExitProcess(uint uExitCode);

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

[return: MarshalAs(UnmanagedType.Bool)]

static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);

static void Main()

{

ExitProcess(1);

//或者

TerminateProcess(Process.GetCurrentProcess().Handle, 1);

}

}

手动发送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事件绑在代码上吧)(一下部分不了解,因为不知道WPF和XAML)

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

{

public partial class MainWindow : Window

{

public MainWindow()

{

InitializeComponent();

}

//Windows消息值

const uint WM_CLOSE = 0x10;

const uint WM_DESTROY = 0x02;

const uint WM_QUIT = 0x12;

//SendMessage和PostMessage的P/Invoke

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

static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtrlParam);

[return: MarshalAs(UnmanagedType.Bool)]

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

static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

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

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

{

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

}

//发送三种消息

private void WM_CLOSE_Click(object sender, RoutedEventArgs e)

{

//也可以用PostMessage

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

}

private void WM_DESTROY_Click(object sender, RoutedEventArgs e)

{

//也可以用PostMessage

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

}

private void WM_QUIT_Click(object sender, RoutedEventArgs e)

{

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

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

}

}

}

时间: 2024-10-18 22:40:54

C#中各种结束进程的方法的相关文章

Android中的跨进程通信方法实例及特点分析(一):AIDL Service

转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481 最近有一个需求就是往程序中加入大数据的采集点,但是因为我们的Android程序包含两个进程,所以涉及到跨进程通信的问题.现将Android中的跨进程通信方式总结如下. Android中有4种跨进程通信方式,分别是利用AIDL Service.ContentProvider.Broadcast.Activity实现. 1.利用AIDL Service实现跨进程通信 这是

Android中的跨进程通信方法实例及特点分析(二):ContentProvider

1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据,Android系统给我们提供了Content Provider使用,通过它能够訪问上面所说的数据.比如非常多音乐播放器中的扫描功能事实上就用到了Content Provider功能(当然,也有的播放器是自己去实现更底层的功能). 这种优点是统一管理,比方添加了某个音频文件,底层就会将这种变化通知Content Provider.从而当应用程序訪问

Linux # Kubuntu 假死,结束进程方法

分析思路: 要知道运行了哪些进程,结束的目标进程是哪些,如何得到运行中的进程,需要哪些操作. 借助搜索引擎,搜索关键字:kconsole 列出进程,查询相关信息,文后参考链接 执行过程: ps aux 列出运行进程 (记录结束的目标进程的 pid,比如 firefox pid 为 22481) 或者 grep firefox ,将显示 22481,即为 pid 接着 kill 22481 ,即可. 备注: 这些命令详细介绍可以看下面链接 参考: Win/Mac/Linux(gnome|kde)

将dll文件注入到其他进程中的一种新方法

http://www.45it.com/windowszh/201212/33946.htm http://www.hx95.cn/Article/OS/201212/65095.html 我们知道将动态连接库注入到其他进程中有很多种方法.最常见的方法是使用钩子函数(Hook),但是这种方法主要有两个缺点:第一如果某个进程没有加载User32.dll,那么Hook DLL将永远也不会被加载.第二Hook DLL加载的时机问题,只有在进程发出User32调用的时候, Hook DLL才有可能被加载

驱动程序中获取当前进程的进程名的方法

在内核驱动程序中,可以通过PsGetCurrentProcess函数来获取当前调用驱动的进程的EPROCESS结构的地址.很多文章都说在EPROCESS结构的0x174偏移处存放着进程名.这里提供另外一种方法来获取这个进程名.思路如下:驱动程序的加载函数DriverEntry是运行在System进程中的.通过PsGetCurrentProcess可以获取System进程的内核EPROCESS结构的地址,然后从该地址开始寻找"System"字符串.找到后,便是EPROCESS的进程名存放

Linux中Kill掉进程的10种方法

常规篇: 首先,用ps查看进程,方法如下: 复制代码 代码如下: $ ps -ef--smx 1822 1 0 11:38 ? 00:00:49 gnome-terminalsmx 1823 1822 0 11:38 ? 00:00:00 gnome-pty-helpersmx 1824 1822 0 11:38 pts/0 00:00:02 bashsmx 1827 1 4 11:38 ? 00:26:28 /usr/lib/firefox-3.6.18/firefox-binsmx 1857

selenium高级应用 - 结束Windows中浏览器的进程

结束Windows中浏览器的进程 #-*- coding:utf-8 #结束Windows中浏览器的进程 from selenium import webdriver import unittest class TestDemo(unittest.TestCase): def test_killWindowsProcess(self): #启动浏览器 firefoxDiver = webdriver.Firefox(executable_path="C:\webdriver_firefox_dr

Linux查看和结束进程命令详解

在ubuntu中,终止一个进程或终止一个正在运行的程序,一般是通过 kill .killall.pkill.xkill 等进行. ------------------------------------------------------------------- 先看两个例子: 例子一:结束某个程序,如Firefox 键入命令: pkill firefox 例子二: 结束某个进程,如find 先用ps命令来查看该进程对应的PID. 键入ps,显示如下: PID TTY TIME COMMAND

fork同时创建多个子进程的方法

Fork同时创建多个子进程方法 第一种方法:验证通过 特点:同时创建多个子进程,每个子进程可以执行不同的任务,程序 可读性较好,便于分析,易扩展为多个子进程 int main(void) { printf("before fork(), pid = %d\n", getpid()); pid_t p1 = fork(); if( p1 == 0 ) { printf("in child 1, pid = %d\n", getpid()); return 0; //若