CantStartSingleInstanceException when trying to start a second instance

I am trying to create a single instance application using the approach described below.

The reason I tried going with this solution was because I needed to pass command lines from the second attempt to run the application in the first instance, and this seemed the easiest way to do this.

OS flavors I need to support:

  • Windows XP SP3
  • Windows 7 32 bit
  • Windows 7 64 bit

I have work on all three OS versions, however I have one machine with Windows 7 32Bit where this happens with a CantStartSingleInstanceException .

Here is the code:

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"); } } } 

For testing purposes, a form is simply a form containing a list that displays command line arguments.

Any ideas why this is not working on this machine? I’ve been doing this for two days and I can’t understand it ...

+4
source share
1 answer

I ran into the same problem, but I don't think it has anything to do with Windows 7 or 32 bits. In my case, this turned out to be a performance issue. Unfortunately, I cannot find the source code for WindowsFormsApplicationBase but it uses the network to communicate with the main application, so timeouts can occur. This is especially bad when the main application has to do a lot of network I / O operations anyway. When the main application does not answer the “Run fast enough” call, this exception is thrown.

I solved this by fine-tuning the processes, tasks and threads, so the call answers first.

And get rid of WindowsFormsApplicationBase with the help of mutexes and the correct IPC, where I can actually not only choose a timeout, but also catch any exceptions! In fact, for some types of IPC there is no need for a mutex.

See this excellent article for more information on this topic: https://www.codeproject.com/Articles/1089841/SingleInstance-NET

Two of the dirtiest workarounds I choose:

  • Catch the exception and try again a couple of milliseconds later.
  • After some testing spawning a new low-priority thread in the base application seems like a good idea (at least that was in my scenario).

     public void SetCommandLineInThread(string[] args) { new Thread(() => { SetCommandLine(args); }) { IsBackground = true, Priority = ThreadPriority.Lowest }.Start(); } 

Please note that I am making a copy of the args command line as soon as possible.

 var args = e.CommandLine.ToArray(); 
+2
source

Source: https://habr.com/ru/post/1401758/


All Articles