4

我有一个 clickonce 应用程序,并且为此应用程序设置了几个文件处理程序(为了这个示例,我想处理带有.aaa.bbb扩展名的文件)。

如果我选择具有这些扩展名之一的单个文件,我的应用程序将按预期启动,一切都很好。但是,如果我选择多个文件并打开它们(通过点击Enter或右键单击并选择Open),那么我的应用程序的多个实例将启动 - 每个选定的文件一个实例。

这不是我所期望的行为,我只希望一个实例以AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. 这可以实现,还是我的期望不正确?

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

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

跟进想法:
在聊完这个问题后,我突然想到这可能只是注册文件处理程序的工作方式,也许它与 clickonce 无关。也许解决方案是让名为 pipe 的服务器在接收到每条消息后暂停并尝试在对消息进行操作之前对消息进行排队?

4

2 回答 2

5

您可以通过实现单个实例应用程序来实现这一点。如果应用程序已经在运行(第二次调用),您可以使用命名管道来通知应用程序(第一次调用)文件打开事件。

编辑

找到一个早期项目的代码片段。我想强调代码肯定需要改进,但这应该是您可以开始的一个好点。

在您的静态主目录中:

        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 秒),单实例服务器将使用文件名列表采取适当的操作

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

我的期望是不正确的 - 您只能将单个文件名传递给已注册的文件处理程序,每个文件名都启动一个单独的处理程序实例。

于 2012-03-03T07:17:14.383 回答