2012-03-16 78 views
4

我在尝试使用概述here的方法构建单个实例应用程序。尝试启动第二个实例时发生CantStartSingleInstanceException

我试着用这个解决方案的原因是,我需要从第二次尝试传递命令行来启动应用程序到第一个实例,这似乎是最简单的方法来完成。

OS口味我需要支持:

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

我得到它的工作在所有三个OS版本,但是,我有一台机器与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"); 
    } 
    } 
} 

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

任何想法,为什么这不适用于一台机器?我已经摆弄这两天了,不知道它...

回答

2

我遇到了同样的问题,但我不认为它与Windows 7或32位有关。结果发现,这是一个性能问题。不幸的是,我找不到WindowsFormsApplicationBase 的源代码,但它使用网络与主应用程序进行通信,因此可能会涉及超时。当主应用程序无论如何需要执行大量的网络I/O时,情况尤其糟糕。当主应用程序未响应足够快的调用时,将抛出此异常。

我解决了它通过微调进程,任务ans线程,所以呼叫得到回答第一。

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

看到这个美好的文章以获得更多关于该主题: https://www.codeproject.com/Articles/1089841/SingleInstance-NET

两个dirtymost解决方法我选择:

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

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

注意,我做的命令行的副本尽快ARG游戏成为可能。

var args = e.CommandLine.ToArray(); 
相关问题