2011-12-16 77 views
4

我有一个clickonce应用程序,并且为此应用程序设置了多个文件处理程序(为了本示例,我想要使用.aaa.bbb扩展名处理文件)。Clickonce应用程序和文件处理程序行为

如果我选择带有这些扩展名之一的单个文件,我的应用程序按预期启动,一切都很好。但是,如果我选择多个文件并打开它们(通过点击输入或右键单击并选择打开),然后启动我的复制副本的多个实例 - 每个文件被选中一个实例。

这不是我期望的行为,我只想要一个实例以AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData中的多个文件条目开始。这可以实现,还是我的期望不正确?

编辑:
只是为了阐述:我们遵循了由@Matthias提到的单个实例方法,首先要启动创建一个名为服务器管道。然后启动后续实例,检测它们是次要的,通过命名管道将其命令行参数(文件名)传递到主实例,然后退出。主实例通过命名管道接收文件名,并执行其操作(启动文件导入向导)。

当用户选择几个文件(即5个文件),然后选择在应用程序中打开这些文件时,就会出现这个问题。我没有获得一个以命令行提供的5个文件名开头的辅助实例,而是获得了5个启动应用程序的辅助实例,每个实例在命令行上都有一个文件名。其中的每一个都会创建一个名为pipe的客户端并将该文件名传递给主实例 - 所以名为pipe的服务器会收到5个单独的消息。

跟进的想法:
聊起这之后发生,我认为也许这只是方式注册的文件处理工作,也许这是不相关的ClickOnce的。也许解决方案是让服务器命名管道在收到每条消息后暂停,并尝试在执行消息之前排队消息?

+0

此行为也适用于赢取窗体应用程序。刚刚尝试过。我想这是无法解决的。 – Matthias 2011-12-16 03:10:08

回答

0

的解决问题的办法是让在管道的服务器端小的延迟。总结:

  • 第一启动的应用程序的实例是管道的服务器端的所有者,该应用程序的后续实例是客户
  • 当从客户端接收消息,开始计时,如果定时器已经启动,那么它被重置。传递的文件名被添加到列表中。
  • 计时器延迟设置为2秒,一次Tick事件发生(所以自上次客户端通信的它已经2秒)的单个实例服务器将采取适当的行动以文件名列表

这不是我期望的行为,我只想要一个实例以AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData中的多个文件条目开始。这可以实现,还是我的期望不正确?

我的期望是不正确的 - 你只能通过一个单一的文件名到注册的文件处理程序,每个文件名启动一个单独的处理程序实例。

5

您可以通过执行single instance application来实现此目的。如果应用程序已经在运行(第二次调用),则可以使用命名管道通知应用程序(第一次调用)文件打开事件。

编辑

发现,从早期的一个项目的代码片段。 我想强调代码绝对需要改进,但它应该是一个很好的起点。

在静态主:

 const string pipeName = "auDeo.Server"; 
     var ownCmd = string.Join(" ", args); 

     try 
     { 
      using (var ipc = new IPC(pipeName)) 
      { 
       Application.EnableVisualStyles(); 
       Application.SetCompatibleTextRenderingDefault(false); 

       var form = new ServerForm(); 

       ipc.MessageReceived += m => 
       { 
        var remoteCmd = Encoding.UTF8.GetString(m); 
        form.Invoke(remoteCmd); 
       }; 
       if (!string.IsNullOrEmpty(ownCmd)) 
        form.Invoke(ownCmd); 

       Application.Run(form); 
      } 
     } 
     catch (Exception) 
     { 
      //MessageBox.Show(e.ToString()); 
      if (string.IsNullOrEmpty(ownCmd)) 
       return; 

      var msg = Encoding.UTF8.GetBytes(ownCmd); 
      IPC.SendMessage(pipeName, msg); 
     } 

的IPC类:

public class IPC : IDisposable 
{ 
    public IPC(string pipeName) 
    { 
     Stream = new NamedPipeServerStream(pipeName, 
              PipeDirection.InOut, 
              1, 
              PipeTransmissionMode.Byte, 
              PipeOptions.Asynchronous); 

     AsyncCallback callback = null; 

     callback = delegate(IAsyncResult ar) 
        { 
        try 
        { 
         Stream.EndWaitForConnection(ar); 
        } 
        catch (ObjectDisposedException) 
        { 
         return; 
        } 

        var buffer = new byte[2000]; 

        var length = Stream.Read(buffer, 0, buffer.Length); 

        var message = new byte[length]; 

        Array.Copy(buffer, message, length); 

        if (MessageReceived != null) 
         MessageReceived(message); 

        Stream.Disconnect(); 

        // ReSharper disable AccessToModifiedClosure 
        Stream.BeginWaitForConnection(callback, null); 
        // ReSharper restore AccessToModifiedClosure 
        }; 

     Stream.BeginWaitForConnection(callback, null); 
    } 

    private NamedPipeServerStream Stream 
    { 
     get; 
     set; 
    } 

    #region IDisposable Members 

    public void Dispose() 
    { 
     if (Stream != null) 
      Stream.Dispose(); 
    } 

    #endregion 

    public static void SendMessage(string pipeName, byte[] message) 
    { 
     using (var client = new NamedPipeClientStream(".", pipeName)) 
     { 
      client.Connect(); 

      client.Write(message, 0, message.Length); 

      client.Close(); 
     } 
    } 

    ~IPC() 
    { 
     Dispose(); 
    } 

    public event MessageHandler MessageReceived; 
} 
+0

这是一个很好的想法,但我们已经在做这个。问题是,我们有多个辅助实例正在启动,它们使用命名管道将文件名传递给主实例,这会启动应用程序中的文件导入向导的多个实例。希望的行为是只启动一个辅助实例,然后将文件名列表传回主实例,从而生成一个文件导入向导实例。 – slugster 2011-12-16 02:35:31