为什么此WPF应用程序无法正确退出?

时间:2013-11-19 08:50:16

标签: c# wpf process task-parallel-library

我在WPF应用程序中有以下代码,在长时间运行的进程发生时显示启动画面。在我们所有的开发人员机器和测试机器上,这都非常有效。但是在某些客户机器上,此代码会使主进程继续运行。

我尝试了各种调用关机的方法,包括Environment.Exit(0);,我们仍然看到此过程在完成后仍然运行。

关于我的任务和应用程序如何交互,我有什么遗漏?

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO.Pipes;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace GKUpdate
{
  /// <summary>
  /// Interaction logic for App.xaml
  /// </summary>
  public partial class App : Application
  {
    protected override void OnStartup(StartupEventArgs e)
    {
      MainWindow oWindow;
      string sPipeName;
      string sGKPath;

      //Call base startup
      base.OnStartup(e);

      //Find the GK path
      sPipeName = FindArgument(e.Args, "n");
      sGKPath = FindArgument(e.Args, "p");

      //Check if we have a path
      if (!string.IsNullOrEmpty(sGKPath))
      {
        //Start listening
        Task.Factory.StartNew(() => ListenForSuccess(sPipeName, sGKPath));

        //Show the splash window
        oWindow = new MainWindow();
        oWindow.Show();
      }
      else
      {
        //Exit
        this.Shutdown();
      }
    }

    private string FindArgument(string[] oArgs, string sArgumentName)
    {
      string sFilter;
      string sArgument;

      //Get the argument
      sFilter = string.Format("/{0}=", sArgumentName).ToLower();
      sArgument = oArgs.FirstOrDefault(x => x.ToLower().StartsWith(sFilter));

      //Check if we found the argument
      if (!string.IsNullOrEmpty(sArgument) && sArgument.Length > sFilter.Length)
      {
        //Set the argument
        sArgument = sArgument.Substring(sFilter.Length).Trim('"');
      }
      else
      {
        //Set null
        sArgument = null;
      }

      //Return the argument
      return sArgument;
    }

    private void ListenForSuccess(string sPipeName, string sGKPath)
    {
      int iStatus;

      try
      {
        //Set default status
        iStatus = -1;

        //Loop until the service is online
        do
        {
          //Create the named pipe
          using (NamedPipeClientStream oNamedPipe = new NamedPipeClientStream(".", sPipeName, PipeDirection.InOut))
          {
            //Connect the pipe allowing 5 mins
            oNamedPipe.Connect(300000);

            //Send the byte asking for a status report
            oNamedPipe.WriteByte(0);
            oNamedPipe.WaitForPipeDrain();

            //Read the return
            iStatus = oNamedPipe.ReadByte();

            //Disconnect
            oNamedPipe.Close();
          }
        } while (iStatus != 1);

        //Check if we can do the success actions
        if (iStatus == 1)
        {
          //Start GateKeeper using the remaining command arguments
          Process.Start(sGKPath, string.Join(" ", Environment.GetCommandLineArgs().Skip(3)));
        }
      }
      catch (Exception)
      {
        //Do nothing
      }
      finally
      {
        //Exit the application
        Application.Current.Dispatcher.InvokeShutdown();
      }
    }
  }
}

4 个答案:

答案 0 :(得分:0)

检查Threads窗口是visual studio。当您的应用程序关闭时,您的一个非后台线程没有运行完成。我希望你现在还在“倾听”。

您如何处理此事取决于您,但我建议您实施task cancellation

答案 1 :(得分:0)

可能有多种原因。首先,您必须检查窗口事件查看器,您将能够找到实际原因。

你也应该处理DispatcherUnhandledException =“Application_DispatcherUnhandledException”。这将显示实际错误。

App.XAML中的

DispatcherUnhandledException="Application_DispatcherUnhandledException"

并在App.cs中:

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{

    e.Handled = true;
}

答案 2 :(得分:0)

您的后台线程被阻塞,等待管道连接。您需要使用oNamedPipe.Close()从前台线程关闭管道。正如Erno de Weerd所说,您还需要确保在管道中止后退出do / while循环。

更好的方法是将CancellationToken传递给任务,并在前台线程请求取消时使用它来关闭管道。然后,您还可以在循环中检查取消状态。

答案 3 :(得分:0)

请参阅How to force Task.Factory.StartNew to a background thread?将Task.Factory.StartNew标记为后台线程,以便一旦所有&#39;前景&#39;线程已停止执行:

  

Task.Factory.StartNew(动作,                         CancellationToken.None,                         TaskCreationOptions.None,                         TaskScheduler.Default).ContinueWith(completeAction);