CantStartSingleInstanceException при попытке запустить второй экземпляр - PullRequest
4 голосов
/ 16 марта 2012

Я пытаюсь создать приложение для одного экземпляра, используя подход, описанный здесь .

Причина, по которой я попытался использовать это решение, заключается в том, что мне нужно передать командные строки со второй попытки запуска приложения на первый экземпляр, и это, казалось, самый простой способ сделать это.

ОС, которые мне нужно поддерживать:

  • 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 Ответ

2 голосов
/ 23 января 2018

Я столкнулся с той же проблемой, но я не думаю, что это как-то связано с Windows 7 или 32bit.В моем случае это оказалось проблемой производительности.К сожалению, я не могу найти исходный код WindowsFormsApplicationBase, но он использует сеть для связи с основным приложением, поэтому возможны тайм-ауты.Это особенно плохо, когда основное приложение все равно должно выполнять много операций сетевого ввода-вывода.Когда основное приложение не отвечает на вызов для запуска достаточно быстро, это исключение выдается.

Я решил эту проблему путем тонкой настройки процессов, задач и потоков, поэтому сначала на вызов отвечали.

И избавился от WindowsFormsApplicationBase с помощью мьютексов и надлежащего IPC, где я на самом деле могу не тольковыберите тайм-аут, но и поймайте любые исключения!На самом деле, для некоторых видов 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();
    }
    

Обратите внимание, что я делаю копию аргументов командной строки как можно скорее.

var args = e.CommandLine.ToArray();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...