处理Windows应用程序的结束过程

时间:2009-05-08 04:38:04

标签: c# .net event-handling

是否可以在同一个Windows应用程序本身内捕获Windows应用程序的任务管理器结束进程?我正在使用一个C#2.0 win应用程序,我想做一些数据库处理(在数据库中将标志从'Y'更改为'N')。

6 个答案:

答案 0 :(得分:10)

不,不可能挂钩操作系统结束进程的决定。注意,这不是由任务管理器完成的,结束一个进程是内核的责任。

你需要在这里做两件事:

  1. 将事件处理程序连接到告诉应用程序退出的普通用户界面消息。使用这些事件来保存数据,释放资源,以及以其他方式彻底退出。
  2. 尽可能处理异常以捕获错误并清理和保存数据。
  3. 以下是Raymond博客的三个链接,解释了为什么你不能按照你的要求去做。

    另外,我解决了类似的StackOverflow问题here

答案 1 :(得分:3)

稍微不同的方法怎么样:

让您的应用更新日期时间字段,例如LastPollDate在运行时经常出现,并且有一个单独的字段,例如“AppTerminatedNormally”,您设置为N,如果您收到表单关闭事件,则更改为Y.

如果应用程序被任务管理器杀死,则日期将不再更新,并且您的AppTerminatedNormally仍然不会。

通过这种方式,您可以运行查询,查找LastPollDate超过10分钟且AppTerminatedNormally为N的所有行,并且您将拥有异常终止的所有会话。

答案 2 :(得分:2)

你们都会在这篇文章中吐痰,但是这里......

您正试图在错误的级别解决问题(即当内核杀死应用时在您的应用中运行代码)。真正的问题是确保数据库正确反映其客户端应用程序的存在(或不存在)。

要解决此问题,请避免允许应用程序在用户交互之间处于“不一致”状态。换句话说,不要启动无法快速提交的事务,不要将数据写入使文件处于半写或不可读状态的文件,并且不要将应用程序外部的资源保留为不一致在用户交互之外的状态。换句话说,如果您的应用程序没有忙于响应事件处理程序,它应该可以立即关闭。

如果您遵循上述做法,您会发现在终止之前需要“快速清理”的情况很少。在用户单击“确定”或“保存”等的交互之外,编写良好的应用程序应该能够立即终止,而不会对其数据存储造成任何持久性损坏或损坏。

如果您必须在退出时在数据库中设置一个标志(这听起来通常用于检测用户是否登录),请考虑以下任一选项:

  1. 定期(可能每30秒一次)在数据库中插入/更新类似时间戳的字段,以指示应用程序最近在线的时间。其他应用程序可以检查这些时间戳以确定最近另一个应用程序在线的时间...如果该值在最后30秒内,则另一个应用程序仍然是在线。

  2. 正如Woodhenge正确建议的那样,创建一个单独的进程(理想情况下是一个服务)来监视主应用程序的状态。可以将Windows服务配置为在服务发生故障时自动重新启动。然后,此监视进程将向数据库发出时间戳。

  3. 请注意,上述两个建议都解决了实际问题(检测应用程序是否正在访问数据库),而不会使数据库处于“不一致状态”(当应用程序实际死亡时,上述标志为“Y”) flag应为“N”)。

答案 3 :(得分:2)

如果您的目标是Windows Vista(或更高版本),您可能会对RegisterApplicationRecoveryCallback API感兴趣...

http://msdn.microsoft.com/en-us/library/aa373345.aspx

它允许您在应用程序中指定一个回调例程,该例程将在进程即将崩溃时调用。注:它仅用于崩溃,如果进程被故意杀死,则不会自动被调用。

你可以从C#调用这个API(我已经完成了),但请记住,当你的回调被调用时你的应用程序已经处于非常糟糕的状态,你可以对状态作出很少的假设你的记忆如果你想在这个例程中使用任何内存中的数据,我会把它放在一个非常通用的静态范围内,以便你有最好的机会在你的回调例程中没有“整理”它运行。

还有一些与此相关的有趣的API,允许您在失败后自动重启应用程序等。

答案 4 :(得分:1)

您可以做的是获取进程ID并监视进程,并且可以使用HasExited属性来检查进程是否已结束。下面是一个快速的VB代码(对不起,我现在没有VS.这是我在另一个论坛上写的)

Public Class Form1
    Dim p As ProcessStartInfo
    Dim process As Process
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        p = New ProcessStartInfo("iexplore.exe")
        process = process.Start(p)
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        MsgBox(process.Id)
        If process.HasExited Then
            MsgBox("yes")
        Else
            MsgBox("no")
        End If
    End Sub
End Class

上面的代码启动Internetexplorer,按钮检查进程是否结束。您可以使用类似的过程来获取所有正在运行的进程并使用processID。

答案 5 :(得分:1)

我认为在应用程序中无法做到这一点。结束任务的目的是立即停止该过程。这不允许执行任何清理代码。

Shoban指出了另一种实现目标的方法。另一个应用程序或服务需要查找主进程。当其他进程找不到主进程时,您可以在那时进行数据库处理。