Using the Clickonce Application and File Handler

I have a clickonce application and I set up several file handlers for this application (for this example, I want to process files with the extensions .aaa or .bbb ).

If I select one file with one of these extensions, my application starts as expected, everything is fine. But if I select several files and open them (either by pressing Enter , or by right-clicking and choosing "Open"), several instances of my application are launched - one instance per selected file.

This is not the behavior that I expected, I want only one instance to start with several file entries in AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData . Can this be achieved, or is my expectation wrong?

Edit:
Just to clarify: we followed a single example, as mentioned in @Matthias, the first instance to run creates a named server pipe. Subsequent instances then start, find that they are secondary, report their command line arguments (file name) through the master instance through the named pipe, and then shut down. The main instance receives the file name through the named pipe and performs its action (launches the file import wizard).

The problem occurs when the user selects several files (i.e. 5 files), then chooses to open these files in the application. Instead of getting one additional instance starting with 5 file names included in the command line, I get 5 secondary instances of the application launch, each of which has one file name on the command line. Then each of them creates a client with the name pipe and passes that file name to the main instance - so that the server with the name pipe receives 5 separate messages.

The following thoughts:
after talking about it, it seems to me that maybe this is just how file handlers work, maybe it’s not related to clickonce. Maybe the solution for the server named pipe is suspended after receiving each message and trying to send messages to the queue before they act?

+4
source share
2 answers

The answer to the problem was to have a slight delay at the end of the server. In short:

  • the first running instance of the application is the owner of the server end; subsequent instances of the application are the client
  • When a message was received from the client, a timer was started, if the timer was already running, it was reset. The missing file name is added to the list.
  • The timer delay was set to 2 seconds, after a tick event occurred (so 2 ​​seconds have passed since the last interaction with the client), one instance server performed the corresponding actions with the list of file names

This is not the behavior that I expected, I want only one instance to start with several file entries in AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Can this be achieved, or is my expectation wrong?

My expectation was wrong - you can transfer only one file name to a registered file handler, each file name starts a separate instance of the handler.

0
source

This can be done by implementing a single instance application . If the application is already running (second call), you can use named pipes to inform the application (first call) about the file open event.

EDIT

A code snippet was found from an earlier project. I want to emphasize that the code definitely needs improvements , but this should be a good point from which you can start.

In your static main:

  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 Class:

 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; } 
+5
source

Source: https://habr.com/ru/post/1386632/


All Articles