0

I currently have an application (.Net Frameowork) that gets triggered via CMD request. I would like to only have one instance of the application running and I would like to handle the arguments being passed in. Right now I have the application identifying if there is a currently running instance.

Example:

  1. cmd ReceiptApplication.exe -r:blah -c:foo
  2. cmd ReceiptApplication.exe -r:blah2 -c:foo2

The second request would pass blah2 and foo2 to the currently running process of ReceiptApplication.exe and kill the second application.

What is the process or pattern for passing the parameters?

using System.Linq;
using System.Windows;

namespace ReceiptApplication
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    /// <summary>
    /// Startup the application, 
    /// Process:
    ///     Get the arguments passed in
    ///     Validate the arguments
    ///     check to see if there is a running instance of the application
    ///     if there is a running app
    ///         Pass the arguments to the running application
    ///         kill the current application. 
    ///     else
    ///         process the request
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        string receiptID = GetArgument(e.Args, "-r");
        string creditUnionFile = GetArgument(e.Args, "-c");
        if(receiptID == null || creditUnionFile == null)
        {
            System.Windows.Forms.Application.Exit();
        }
        if (AppCurrntlyRunning())
        {
            //pass arguments to the current running application
            Process alreadyRunningApplication = GetOriginalProcess();
            var streamWriter = alreadyRunningApplication.StandardInput;
            streamWriter.WriteLine("-r:blah -c:yay");

            //kill this one
            System.Windows.Forms.Application.Exit();
        }
        MessageBox.Show("Starting UI!");
        MainWindow wnd = new MainWindow();
        wnd.PullReceipt(receiptID, creditUnionFile);
        wnd.Show();
    }
}
}
Sari Rahal
  • 1,897
  • 2
  • 32
  • 53
  • Do you want to pass information to your application during runtime? I am not sure what is your question here. – 66Gramms Sep 22 '21 at 14:25
  • You could try [the same I did](https://github.com/PieterjanDeClippel/SingleInstanceAppDemo/blob/master/SingleInstanceAppDemo/Program.cs) some long, long time ago. [Here's a more recent version](https://github.com/PieterjanDeClippel/DrawIt/blob/master/DrawIt/Program.cs) that uses named pipes for **inter-process communication**. – Pieterjan Sep 22 '21 at 14:29
  • 1
    @66Gramms, I've updated the question to have an example. – Sari Rahal Sep 22 '21 at 14:33
  • Command-line parameters are passed only when the application starts. When the application is already running, it is impossible to pass anything to it using parameters. You should use [inter-process communication](https://en.wikipedia.org/wiki/Inter-process_communication). Named pipes is a good choice. A couple more useful links: [Interprocess Communications](https://learn.microsoft.com/en-us/windows/win32/ipc/interprocess-communications), [How to: Use Anonymous Pipes](https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-use-anonymous-pipes-for-local-interprocess-communication) – Alexander Petrov Sep 22 '21 at 17:17
  • @AlexanderPetrov : I think that might be what i'm looking for. I'll have to do some coding and testing to let you know if it works out. Thanks. – Sari Rahal Sep 22 '21 at 20:52

1 Answers1

1

If you want to pass information to your application during runtime you could use the standard input stream. This is how it's done: How to write to stdin in C# Then in your running application you can read the written data with Console.ReadLine();

On the linked answer on how to write to stdin in C# mind that instead of starting a new application you want to store a reference to your already running one:

//DON'T do this
//var process = new Process();
//process.StartInfo = startInfo;
//process.Start();
        
//DO this
var processes =  Process[] localByName = Process.GetProcessesByName("The Title Of My Application"); //This should give back multiple processes if you start your application for a second time so be mindful about that
Process alreadyRunningApplication;
if(processes.Length > 1)
{
    if (processes[0].Id == Process.GetCurrentProcess.Id)
    {
        alreadyRunningApplication = processes[1];
    }
    else
    {
        alreadyRunningApplication = processes[0];
    }
    var streamWriter = alreadyRunningApplication.StandardInput;
    streamWriter.WriteLine("I'm supplying input!");
}
else
{
//If we get into this else, it means this instance is the first running instance so your normal program behavior should go here for example using Console.ReadLine();
}
66Gramms
  • 769
  • 7
  • 23
  • I don't think that's what I'm looking for. I think that's fine if the application isn't already running and it's on startup. I'm trying to pass parameters to an application already running and the application is the exact same application calling it. That solution would just be an endless loop, wouldn't it? – Sari Rahal Sep 22 '21 at 14:49
  • @SariRahal I've added a code example, this shouldn't be an endless loop – 66Gramms Sep 22 '21 at 15:04
  • I've implemented the code and I get the correct process, but when it get's to the "StandardInput" I receive an error. This exception was originally thrown at this call stack: [External Code] ReceiptApplication.App.Application_Startup(object, System.Windows.StartupEventArgs) in App.xaml.cs [External Code] – Sari Rahal Sep 22 '21 at 15:27
  • What exception you recive? – 66Gramms Sep 22 '21 at 15:30
  • System.InvalidOperationException: 'StandardIn has not been redirected.' – Sari Rahal Sep 22 '21 at 15:31
  • According to [MS Docs](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.redirectstandardinput?view=net-5.0#System_Diagnostics_ProcessStartInfo_RedirectStandardInput) You have to redirect the standard input, I'll include that in the answer as well, I just didn't know about this as I haven't used this before. – 66Gramms Sep 22 '21 at 15:32
  • I've updated the question to show the current state with your answer. – Sari Rahal Sep 22 '21 at 15:34
  • As far as I see there is no way to enable the redirection of standard input inside your application, only if you start it from an already running process? This seems really weird to me, more research need to be done on the topic. Maybe this is really not a solution for you – 66Gramms Sep 22 '21 at 15:37
  • could you delete this answer to get more attention to the question. – Sari Rahal Sep 22 '21 at 18:07