4

Clickonceアプリケーションがあり、このアプリケーション用にいくつかのファイルハンドラーを設定しました(この例では、.aaaまたは.bbb拡張子のいずれかを持つファイルを処理します)。

これらの拡張子のいずれかを持つ単一のファイルを選択すると、アプリケーションは期待どおりに起動し、すべてが正常に機能します。しかし、複数のファイルを選択して(を押すEnterか、右クリックして[開く]を選択して)開くと、アプリケーションの複数のインスタンスが起動します(選択したファイルごとに1つのインスタンス)。

これは私が期待した動作ではありません。1つのインスタンスだけで、の複数のファイルエントリから開始する必要がありますAppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData。これは達成できますか、それとも私の期待は正しくありませんか?

編集:
詳しく説明します。@ Matthiasで説明されているように、単一インスタンスのアプローチに従いました。最初に起動するインスタンスは、名前付きサーバーパイプを作成します。その後、後続のインスタンスが起動し、セカンダリであることを検出し、コマンドライン引数(ファイル名)を名前付きパイプを介してメインインスタンスに伝達し、終了します。メインインスタンスは名前付きパイプを介してファイル名を受け取り、その処理を実行します(ファイルインポートウィザードを起動します)。

この問題は、ユーザーが複数のファイル(つまり、5つのファイル)を選択してから、アプリケーションでそれらのファイルを開くことを選択した場合に発生します。コマンドラインで指定された5つのファイル名で始まる1つのセカンダリインスタンスを取得する代わりに、コマンドラインでそれぞれ1つのファイル名を持つアプリケーションの5つのセカンダリインスタンスを取得しています。次に、これらのそれぞれがパイプという名前のクライアントを作成し、そのファイル名をメインインスタンスに伝達します。したがって、パイプという名前のサーバーは5つの個別のメッセージを受信します。

フォローアップの考え:
これについてチャットした後、おそらくこれは登録されたファイルハンドラーの動作方法であり、clickonceとは関係がない可能性があります。おそらく解決策は、pipeという名前のサーバーが各メッセージを受信した後に一時停止し、メッセージを実行する前にメッセージをキューに入れようとすることですか?

4

2 に答える 2

5

これは、単一インスタンスアプリケーションを実装することで実現できます。アプリケーションがすでに実行されている場合(2回目の呼び出し)、名前付きパイプを使用して、ファイルを開くイベントをアプリケーションに通知できます(最初の呼び出し)。

編集

以前のプロジェクトのコードスニペットが見つかりました。コードには間違いなく改善が必要であることを強調したいのですが、それはあなたが始めることができる良い点であるはずです。

静的メイン:

        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;
}
于 2011-12-16T02:26:14.783 に答える
0

この問題に対する答えは、パイプのサーバー側でわずかな遅延を発生させることでした。要約すれば:

  • アプリの最初に開始されたインスタンスはパイプのサーバー側の所有者であり、アプリの後続のインスタンスはクライアントです
  • クライアントからメッセージを受信すると、タイマーが開始されました。タイマーがすでに開始されている場合は、タイマーがリセットされました。渡されたファイル名がリストに追加されます。
  • タイマー遅延は2秒に設定され、ティックイベントが発生すると(つまり、最後のクライアント通信から2秒でした)、単一インスタンスサーバーはファイル名のリストを使用して適切なアクションを実行します。

これは私が期待した動作ではありません。1つのインスタンスをAppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationDataの複数のファイルエントリで開始する必要があります。これは達成できますか、それとも私の期待は正しくありませんか?

私の予想は正しくありませんでした。登録されたファイルハンドラーに渡すことができるのは単一のファイル名のみであり、各ファイル名はハンドラーの個別のインスタンスを開始します。

于 2012-03-03T07:17:14.383 に答える