2011-12-16 83 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