如何在程序里面判断程序进程被强制关闭了

.net写的控制台程序,如果是控制台正常关闭,可以用ProcessExit判定,可是如果程序本身是被强制退出的,比如有人在任务管理器上杀进程,这有办法能捕获到吗?
因为我需要在程序被退出时,做一些逻辑。。。

这个问题得分为两方面来讲。
第一,被任务管理器的“进程”面板关闭的进程不可能进行任何清理工作,这是OS的设计。(不这样设计的话,假设你关机时有个进程一直卡死,你就永远没办法通过软件关机了。)
第二,尽管如此,在多数异常退出情形下,你仍然可以让你的程序响应信号并进行清理工作。
====分割线====
CS的话我不太懂,但C/C++的话,可以通过signal.h这个C库(是标准库的一部分)来处理多数异常退出情形。通过signal函数可以(暂时地)更换指定信号的回调函数。


signal | Microsoft Docs https://docs.microsoft.com/en-us/previous-versions/xdkz3x12(v=vs.140)

这两个链接中,第一个是POSIX(Unix标准)的,第二个是MSDN(Windows标准)的,Unix的信号比Windows的多,但也兼容。
默认会终止进程的信号基本有以下几个:
SIGKILL:Windows下没有,用于强制关闭进程,进程不会有任何进行清理工作的机会。在Windows任务管理器的进程面板结束进程的效果等同于Unix下发送SIGKILL。不能忽略,不能做任何其他处理。
SIGTERM:要求关闭进程,但进程可以忽略该信号(但一般不建议忽略)。例如,用户尝试关机时,进程会收到这个信号。某些场景下,如果进程收到SIGTERM后一段时间内没有结束,就会被强制终止,因此收到信号后应当尽快执行最后的操作。
SIGABRT:一般在调用abort函数后触发。似乎比较少见。
SIGFPE:浮点运算错误,也可能不会触发程序终止。
SIGILL:错误的二进制指令,很少见,除非程序损坏了,否则不会遇到。
SIGINT:输入Ctrl+C组合键触发的用户中断,会终止进程,但是可以忽略,可以处理。
SIGSEGV:由段错误触发,比较典型的情形是试图访问野指针指向的位置。除非决定通过setjmp处理,否则不要管它,这一般是软件代码bug导致的。
====分割线====
如果你指的是要查看子进程的情况,那恐怕没有什么特别好的跨平台方法。
如果是Unix下就好办了,直接查man手册的wait方法,它可以获取子进程的一切状态。
Windows的话,根据MSDN的官方文档,应该没什么办法。通过CreateProcess系列函数启动进程后就只有通过GetExitCodeProcess来获得进程退出代码,而这个退出代码可能是main函数返回的值,可能是exit函数的值,可能是TerminateProcess或ExitProcess函数设定的值,还可能是异常和信号设置的异常值,而且没有区分方法,你只能试图避开这些Windows内部设置好的值,以免和正常的返回内容混淆。最好的做法就是:除非有必要,否则别在主函数里面返回任何除了0以外的东西,因为0一定表示正常退出。一定需要不同进程间交换信息的话,你可以在CreateProcess调用中重定向IO流,或者开个管道之类的,当然也可以用其他IPC手段。

感谢楼上的回答,也给了我一些关于“杀进程机制”启发。
这个问题刚刚解了,虽然解决的方式其实蛮令我“不解”的,这里说明一下我的解法吧。
我的需求是在程式退出之前,需要有一段手动跟Server端清理subscription的特殊处理(跨到OPC UA连线机制去了,这里不引申),但控制台这个黑色小框框很容易被操作人员随手叉掉造成误关闭,所以目前这个程序是被nssm打包成windows服务在后台跑。
首先我想到了曲线救国,既然强杀进程这事儿是OS的机制,而正常关闭程序的话,捕获这个事件的骚操作还是不少的,那我也不纠结那么多了,换个思路曲线救国吧。
我打算调整部署方式,改成把控制台正常打开放在前台运行,不用nssm包成后台服务了。然后调WindowsAPI把控制台的关闭按钮禁用掉,提高操作人员手贱关闭程序的门槛。当真的需要关闭程序触发我手动释放资源的逻辑,宣导操作人员必须由键盘输入CTRL+C进行,随后在Main函数里面来一段——

Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
//做爱做的事
e.Cancel = false;
};

然后运行了一下,CTRL+C强制退出,检查log,嗯,需要的清理代码被执行了,看起来效果不错。
本来都打算就这样跟现场使用者讲了,鬼使神差的,我又试了下把这个控制台重新用nssm打包成windows服务,在服务那里进行重启。打开log,居然发现做爱做的事依然被执行到了!
我的问题解了?!
所以,看起来控制台程序的话,使用CancelKeyPress可以捕获到杀进程?于是我回到正常开控制台程序的方式,打开任务管理器,右击杀进程,再看log,好吧,什么也没发生。
所以说这个问题只能算是“阴差阳错”被解决了,不是很懂背后的原理。有看懂我这个故事背后真相的大神麻烦补个贴。。。
总结:
1.使用CancelKeyPress可以捕获到控制台被强制退出的事件,即便是这个控制台程序是以系统服务在后台跑的时候被人关闭或重启,依然能被CancelKeyPress捕获到(提问前,我已经用AppDomain.CurrentDomain.ProcessExit测试过,并不行)
2.任务管理器那边结束进程属于OS的机制,霸道而且无情。。。