尝试启动第二个实例时,CantStartSingleInstanceException

时间:2012-03-16 08:32:48

标签: c# single-instance

我尝试使用概述here的方法构建单个实例应用程序。

我尝试使用该解决方案的原因是我需要将第二次尝试启动应用程序的命令行传递给第一个实例,这似乎是实现这一目标的最简单方法。

我需要支持的操作系统风格:

  • Windows XP SP3
  • Windows 7 32位
  • Windows 7 64位

我已经在所有三个操作系统版本上工作了,但是,我有一台机器使用Windows 7 32Bit,其中CantStartSingleInstanceException崩溃了。

以下是代码:

SingleInstanceController.cs:

using System;
using Microsoft.VisualBasic.ApplicationServices;

namespace SingleInstanceTest
{
  public class SingleInstanceController : WindowsFormsApplicationBase
  {
    public SingleInstanceController()
    {
      IsSingleInstance = true;
    }

    protected override void OnCreateMainForm()
    {
      base.OnCreateMainForm();

      Form1 f = new Form1();
      MainForm = f;

      // process first command line
      f.SetCommandLine(Environment.GetCommandLineArgs());
    }

    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
      base.OnStartupNextInstance(eventArgs);

      Form1 f = MainForm as Form1;

      // process subsequent command lines
      f.SetCommandLine(eventArgs.CommandLine);
    }
  }
}

的Program.cs:

using System;
using System.Windows.Forms;

namespace SingleInstanceTest
{
  static class Program
  {
    [STAThread]
    static void Main()
    {
      AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
      Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      SingleInstanceController si = new SingleInstanceController();

      // This triggers the crash on one machine when starting the
      // app for the second time
      si.Run(Environment.GetCommandLineArgs());
    }

    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
      // this is triggered with CantStartSingleInstanceException
      MessageBox.Show(e.ToString(),"ThreadException");
      MessageBox.Show(e.Exception.ToString(), "ThreadException");
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
      MessageBox.Show(e.ToString(), "UnhandledException");
      MessageBox.Show(e.ExceptionObject.ToString(), "UnhandledException");
    }
  }
}

出于测试目的,表单只是一个包含显示命令行参数的列表框的普通表单。

为什么这不适用于那台机器的任何想法?我现在已经花了两天时间摆弄这个并且无法解决这个问题......

1 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,但我认为它与Windows 7或32位无关。事实证明,这是一个性能问题。不幸的是,我无法找到WindowsFormsApplicationBase的源代码 但它使用网络与主应用程序通信,因此可能涉及超时。当主应用程序不得不做很多网络I / O时,它尤其糟糕。当主应用程序没有快速响应Run to Run的调用时,抛出此异常。

我通过微调进程,任务和线程来解决它,因此首先回答了调用。

通过使用互斥锁和适当的IPC来摆脱WindowsFormsApplicationBase,我实际上不仅可以选择超时,还可以捕获任何异常!实际上,对于某些类型的IPC,甚至不需要互斥锁。

有关该主题的更多信息,请参阅此精美文章: https://www.codeproject.com/Articles/1089841/SingleInstance-NET

我选择的两个最脏的解决方法:

  1. 捕获异常并在几毫秒后再次尝试。
  2. 经过一些测试,在基础应用程序中生成一个低优先级的新线程似乎是一个好主意(至少在我的场景中)。

    public void SetCommandLineInThread(string[] args) {
        new Thread(() => {
            SetCommandLine(args);
        }) { IsBackground = true, Priority = ThreadPriority.Lowest }.Start();
    }
    
  3. 请注意,我会尽快复制命令行参数。

    var args = e.CommandLine.ToArray();