【问题标题】:Process.Kill() related crashesProcess.Kill() 相关的崩溃
【发布时间】:2009-05-06 20:11:26
【问题描述】:

还是不行!

我有一个相当简单的应用定时器程序。该程序将启动用户选择的(从文件对话框)可执行文件,然后在用户指定的分钟数后终止该过程。在测试过程中我发现当我调用 Process.Kill() 方法并且应用程序被最小化到系统托盘时发生了崩溃。

有问题的可执行文件是我经常使用的 Frap.exe,这也是我首先编写应用计时器的原因。我总是尽量减少托盘的碎片,这就是崩溃发生的时候。

我对 Kill() 的使用非常简单......

while (true)
        {
            //keep checking if timer expired or app closed externally (ie. by user)
            if (dtEndTime <= DateTime.Now || p.HasExited)
            {
                if (!p.HasExited)
                    p.Kill();
                break;
            }
            System.Threading.Thread.Sleep(500);
        }

在寻找以编程方式关闭外部应用程序的替代方法时,我发现只有 Close() 和 Kill()(CloseMainWindow 对我一点帮助都没有)。我尝试使用 Close(),它可以在应用程序最小化托盘的情况下工作。如果应用程序被最小化, Close() 不会导致崩溃,但应用程序保持打开和活动状态。 我在一些关于关闭外部应用程序的帖子中注意到的一件事是评论:“我个人会尝试找到一种更优雅的方式来关闭它。”在堆栈流中找到的THIS 线程中制作(对约翰没有冒犯)。问题是,我在一些网站上遇到过这样的 cmets,但没有尝试过优雅或优雅(或无崩溃!!)的方法。

有什么建议吗?

经历的崩溃并不一致,我几乎无法提供细节。当我收到消息时,我无法使用 VS2008 进行调试 - 无法调试崩溃的应用程序(或类似的东西),并且取决于我当时运行的其他程序,当调用 Kill() 时,其中一些也会崩溃(还有程序仅在托盘中运行)所以我认为这是与系统托盘特别相关的某种问题。

【问题讨论】:

  • 您是否尝试将 ALT+F4 发送到应用程序?
  • 没有。老实说,我不知道该怎么做。我所做的唯一进程间通信是在我自己的应用程序之间使用管道和端口(套接字)。我会调查的,但如果你有什么具体的,请随意......

标签: c#


【解决方案1】:

您的代码是否可能以某种方式执行,以至于有时会调用两次 Kill() 语句?在 Process.Kill() 的文档中,它说 Kill 异步执行。因此,当您调用 Kill() 时,会在您的主线程上继续执行。此外,文档指出,如果您在已经处于关闭过程中的应用程序上调用 Kill,它将引发 Win32Exception。文档声明您可以使用 WaitForExit() 等待进程退出。如果在调用 Kill() 之后立即调用 WaitForExit() 会发生什么。循环看起来不错(使用 break 语句)。是否有可能您的代码两次进入该循环?

如果这不是问题,也许还有另一种方法可以捕获该异常: 尝试挂钩 AppDomain.CurrentDomain.UnhandledException 事件 (currentDomain 是静态成员)

问题是 Kill 异步运行,所以如果它抛出异常,它就会发生在不同的线程上。这就是您的异常处理程序没有捕获它的原因。此外(我认为)未处理的异步异常(我相信您拥有)将导致您的应用程序立即卸载(正在发生的事情)。

编辑:挂钩 UnhandledExceptionEvent 的示例代码 这是一个简单的控制台应用程序,演示了 AppDomain.UnhandledException 的使用:

using System; public class MyClass { public static void Main() { System.AppDomain.CurrentDomain.UnhandledException += MyExceptionHandler; System.Threading.ThreadPool.QueueUserWorkItem(DoWork); Console.ReadLine(); } private static void DoWork(object state) { throw new ApplicationException("Test"); } private static void MyExceptionHandler(object sender, System.UnhandledExceptionEventArgs e) { // get the message System.Exception exception = e.ExceptionObject as System.Exception; Console.WriteLine("Unhandled Exception Detected"); if(exception != null) Console.WriteLine("Message: {0}", exception.Message); // for this console app, hold the window open until I press enter Console.ReadLine(); } }

【讨论】:

  • 谢谢...我将不得不考虑你提到的挂钩 - 尽管我基本上对如何实现它一无所知。我将从阅读 AppDomain 开始……看看我能从那里找出什么。我接受了您的建议,使用 WaitForExit() 进行了测试并确认它返回 true - 我打开一个消息框 - 但我仍然崩溃。此外,我还发现,如果我在 Fraps 应用程序计时时将其最小化,即使我将其重新启动(最大化)我也会崩溃。但如果我不最小化,根本不会崩溃。
  • 你知道——当我最初写响应时,我有示例代码,但搞砸了并关闭了我的编辑器而不保存它!我在今天的回复中又举了一个例子。也许这将有助于获得一些诊断信息。至少,我很高兴您找到了解决方法。问候。
【解决方案2】:

我的第一个想法是在 Kill() 调用周围放置一个 try/catch 块,并记录你得到的异常,如果有的话。它可能会让你知道出了什么问题。比如:

try 
{
    if(!p.HasExited)
    {
        p.Kill();
    }
    break;
}
catch(Exception ex)
{
    System.Diagnostics.Trace.WriteLine(String.Format("Could not kill process {0}, exception {1}", p.ToString(), ex.ToString()));
}

【讨论】:

  • 对,Process.Kill() 可以产生几种可能的异常——通过查看它抛出的问题应该是清楚的。
  • 实际代码在 try 块中有 'if',我只是将其删除以保持帖子更干净。事情是,我没有从 catch 中得到任何东西 - 尝试使用特定的异常错误捕获,以及包罗万象的“catch{ //code }”无济于事。崩溃完全消除了 VS - 没有任何可用的调试,尽管可以选择在这个或另一个无法加载的 VS 实例中进行调试。此外,正在调用应用程序 Kill() 以关闭。我只能得出结论,Fraps 实际上是导致崩溃的原因,但我仍然需要一种方法来处理它(即“优雅地”杀死 Fraps)
  • 奇怪。我刚刚下载了 fraps 并从命令行尝试了“taskkill /f /im fraps.exe”,看看会发生什么,各种应用程序都崩溃了。我想为了发挥它的魔力,fraps 一定是在钩住应用程序,所以杀死它可能是一件坏事。我建议使用类似stackoverflow.com/questions/436430/… 的技术将 Alt-F4 发送到其主窗口。
【解决方案3】:

我认为我不应该声称这是“答案”,但它是一个不错的“解决方法”。将以下内容添加到代码行中...

p.WaitForInputIdle(10000);
am.hWnd = p.MainWindowHandle;

...停止了崩溃问题。这些行紧跟在 Process.Start() 语句之后。两条线都是必需的,在使用它们时,我打开了其他一些问题的大门,我将在接下来的几天内调查这些问题。第一行只是等待启动的进程“空闲”(即完成启动)最多 10 秒。 am.hWnd 是我的 IntPtr 类型的 AppManagement 类中的一个属性,这是分配双方的唯一用法。由于缺乏更好的解释,这两行与去抖动方法是相似的。

我只稍微修改了 while 循环,以允许调用 CloseMainWindow(),这似乎是更好的选择 - 尽管如果失败,我会 Kill() 应用程序:

while (true)
{
   //keep checking if timer expired or app closed externally (ie. by user)
   if (dtEndTime <= DateTime.Now || p.HasExited)  {
      try {
          if (!p.HasExited)  // if the app hasn't already exitted...
          {
             if (!p.CloseMainWindow())  // did message get sent? 
             {
                if (!p.HasExited)  //has app closed yet?
                {
                   p.Kill();  // force app to exit
                   p.WaitForExit(2000);  // a few moments for app to shut down
                }
             }
             p.Close();  // free resources
          }                        
       }
      catch { // blah blah }
      break;
   }
   System.Threading.Thread.Sleep(500);
}

我获取 MainWindowHandle 的最初目的是最大化/还原应用程序(如果已最小化),我可能会在不久的将来实现它。我决定看看其他程序是否像 Fraps 一样运行(即,一个 UI,但主要在系统托盘中运行(如 Yahoo 等的 messanger 服务))。我用 XFire 进行了测试,但我无能为力地返回 MainWindowHandle 的值。无论如何,这是一个单独的问题,但我觉得很有趣。

PS。 JMarsch 有点功劳,因为他的建议 RE: Win32Exception 实际上让我找到了这项工作 - 看起来不太可能。

【讨论】:

  • 谢谢!我很高兴它有帮助!不过我和你在一起,看来应该有更好的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多