/// <summary> /// Called when the form is loading. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void FormMain_Load(object sender, EventArgs e) { string[] arguments = Environment.GetCommandLineArgs(); if (arguments.Length >= 2) { string arg = arguments[1].ToUpper(); if (arg == "/?" || arg == "?") { var usage = @"MutexSingleInstanceAndNamedPipe [/Close] | [Test option1] [Test option nn]"; MessageBox.Show(usage, Text, MessageBoxButtons.OK, MessageBoxIcon.Information); Close(); return; } if (arg == "/CLOSE" || arg == "CLOSE") { // If we are not the first instance, send a quit message along the pipe if (!IsApplicationFirstInstance()) { var namedPipeXmlPayload = new NamedPipeXmlPayload { SignalQuit = true }; // Send the message NamedPipeClientSendOptions(namedPipeXmlPayload); } // Stop loading form and quit Close(); return; } } // If are the first instance then we start the named pipe server listening and allow the form to load if (IsApplicationFirstInstance()) { // Create a new pipe - it will return immediately and async wait for connections NamedPipeServerCreateServer(); } else { // We are not the first instance, send the named pipe message with our payload and stop loading var namedPipeXmlPayload = new NamedPipeXmlPayload { SignalQuit = false, CommandLineArguments = Environment.GetCommandLineArgs().ToList() }; // Send the message NamedPipeClientSendOptions(namedPipeXmlPayload); // Stop loading form and quit Close(); } }
/// <summary> /// The function called when a client connects to the named pipe. Note: This method is called on a non-UI thread. /// </summary> /// <param name="iAsyncResult"></param> private void NamedPipeServerConnectionCallback(IAsyncResult iAsyncResult) { try { // End waiting for the connection _namedPipeServerStream.EndWaitForConnection(iAsyncResult); // Read data and prevent access to _namedPipeXmlPayload during threaded operations lock (_namedPiperServerThreadLock) { // Read data from client var xmlSerializer = new XmlSerializer(typeof(NamedPipeXmlPayload)); _namedPipeXmlPayload = (NamedPipeXmlPayload)xmlSerializer.Deserialize(_namedPipeServerStream); // Need to signal quit? if (_namedPipeXmlPayload.SignalQuit) { NamedPipeThreadEvent_Close(); return; } // _namedPipeXmlPayload contains the data sent from the other instance // As an example output it to the textbox // In more complicated cases would need to do some processing here and possibly pass to UI thread TextBoxAppend(_namedPipeXmlPayload); } } catch (ObjectDisposedException) { // EndWaitForConnection will exception when someone calls closes the pipe before connection made // In that case we dont create any more pipes and just return // This will happen when app is closing and our pipe is closed/disposed return; } catch (Exception) { // ignored } finally { // Close the original pipe (we will create a new one each time) _namedPipeServerStream.Dispose(); } // Create a new pipe for next connection NamedPipeServerCreateServer(); }
/// <summary> /// Appends string version of the payload to the end of the text box. Handles being called from a non UI thread. /// </summary> private void TextBoxAppend(NamedPipeXmlPayload namedPipeXmlPayload) { if (textBoxOutput.InvokeRequired) { textBoxOutput.Invoke((MethodInvoker) delegate { TextBoxAppend(namedPipeXmlPayload); }); return; } string message = "SignalQuit: " + namedPipeXmlPayload.SignalQuit; foreach (string commandLine in namedPipeXmlPayload.CommandLineArguments) { message += "\r\nCommandLine: " + commandLine; } textBoxOutput.Text += message + "\r\n\r\n"; }
/// <summary> /// Uses a named pipe to send the currently parsed options to an already running instance. /// </summary> /// <param name="namedPipePayload"></param> private void NamedPipeClientSendOptions(NamedPipeXmlPayload namedPipePayload) { try { using (var namedPipeClientStream = new NamedPipeClientStream(".", PipeName, PipeDirection.Out)) { namedPipeClientStream.Connect(3000); // Maximum wait 3 seconds var xmlSerializer = new XmlSerializer(typeof(NamedPipeXmlPayload)); xmlSerializer.Serialize(namedPipeClientStream, namedPipePayload); } } catch (Exception) { // Error connecting or sending } }