Приложение Clickonce и поведение обработчика файлов - PullRequest
4 голосов
/ 16 декабря 2011

У меня есть приложение clickonce, и я настроил несколько обработчиков файлов для этого приложения (для примера я хочу обрабатывать файлы с расширениями .aaa или .bbb).

Если я выберу один файл с одним из этих расширений, мое приложение запустится как положено, все хорошо.Но если я выберу несколько файлов и открою их (нажав Enter или щелкнув правой кнопкой мыши и выбрав Open ), то будет запущено несколько экземпляров моего приложения - один экземпляр на файл, которыйбыло выбрано.

Это не то поведение, которое я ожидал, я хочу, чтобы только один экземпляр запускался с несколькими записями в AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData.Может ли это быть достигнуто, или мои ожидания неверны?

Редактировать:
Просто чтобы уточнить: мы следовали подходу с одним экземпляром, как упомянуто @Matthias, первым экземпляром, который нужно запуститьup создает именованный канал сервера.Затем запускаются последующие экземпляры, обнаруживают, что они являются вторичными, передают свои аргументы командной строки (имя файла) через основной экземпляр через именованный канал, а затем завершают работу.Основной экземпляр получает имя файла через именованный канал и делает свое дело (запускает мастер импорта файлов).

Проблема возникает, когда пользователь выбирает несколько файлов (то есть 5 файлов), а затем выбирает, чтобы открыть эти файлы в приложении.Вместо того, чтобы получить один вторичный экземпляр, начинающийся с 5 имен файлов, указанных в командной строке, я получаю 5 вторичных экземпляров запуска приложения, каждый с одним именем файла в командной строке.Затем каждый из них создает клиентский канал с именем pipe и сообщает это имя файла основному экземпляру, поэтому именованный канал сервера получает 5 отдельных сообщений.

Последующие мысли:
после разговора оЭто происходит со мной, что, возможно, именно так работают зарегистрированные обработчики файлов, возможно, это не связано с clickonce.Может быть, решение заключается в том, чтобы сервер с именованным каналом приостанавливал работу после получения каждого сообщения и пытался ставить сообщения в очередь перед их действием?

Ответы [ 2 ]

5 голосов
/ 16 декабря 2011

Этого можно добиться, внедрив приложение для одного экземпляра .Если приложение уже запущено (второй вызов), вы можете использовать именованные каналы для информирования приложения (первый вызов) о событии открытия файла.

EDIT

Найденофрагмент кода из более раннего проекта. Я хочу подчеркнуть, что код определенно нуждается в улучшениях , но это должен быть хороший момент, с которого вы можете начать.

В вашей статической главной:

        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);
        }

Класс МПК:

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 голосов
/ 03 марта 2012

Ответом на проблему была небольшая задержка на конце канала для сервера. В итоге:

  • первый запущенный экземпляр приложения является владельцем серверной части канала, последующие экземпляры приложения являются клиентом
  • При получении сообщения от клиента был запущен таймер, если таймер уже был запущен, то он был сброшен. Переданное имя файла добавляется в список.
  • Задержка таймера была установлена ​​равной 2 секундам, после того, как произошло событие галочки (таким образом, прошло 2 секунды с момента последнего взаимодействия с клиентом), сервер единого экземпляра предпримет соответствующее действие со списком имен файлов

Это не то поведение, которого я ожидал, я хочу, чтобы только один экземпляр запускался с нескольких записей в файле AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Это может быть достигнуто, или мои ожидания неверны?

Мое ожидание было неверным - вы можете передать только одно имя файла зарегистрированному обработчику файлов, каждое имя файла запускает отдельный экземпляр обработчика.

...