Pass arguments to running application

27,023

Solution 1

I have figured it out, so awesome thanks for the person who posted the http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/a5bcfc8a-bf69-4bbc-923d-f30f9ecf5f64 link, this is exactly what I was looking for!

Here's a the full solution:

static class Program
{
    [STAThread]
    static void Main(params string[] Arguments)
    {
        SingleInstanceApplication.Run(new ControlPanel(), NewInstanceHandler);
    }

    public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
    {
        string imageLocation = e.CommandLine[1];
        MessageBox.Show(imageLocation);
        e.BringToForeground = false;
        ControlPanel.uploadImage(imageLocation);
    }

    public class SingleInstanceApplication : WindowsFormsApplicationBase
    {
        private SingleInstanceApplication()
        {
            base.IsSingleInstance = true;
        }

        public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
        {
            SingleInstanceApplication app = new SingleInstanceApplication();
            app.MainForm = f;
            app.StartupNextInstance += startupHandler;
            app.Run(Environment.GetCommandLineArgs());
        }
    }  
}

Thanks alot all, and especially the person who posted that link I mentioned above but I guess he deleted his answer?

Regards, Kenny

Solution 2

Well you will have to establish a communication channel for other applications to post the images to. This communication channel can be one of the following - not a complete list just samples:

  • A directory that is watched by your app and the file is added once it is added to the directory.
  • A port where other applications can send information to.
  • A self-hosted web service that accepts the images.
  • A TCP port that receives the images.
  • A named pipe.
  • ....

As you see there are several possibilities. The right one for you depends on your scenario. The file system is an option that can be implemented easily using a FileSystemWatcher for a sample see here.

A self-hosted web sevice exposes a web service that can receive images. See here for a sample.

IMHO, these are the two options that are easiest. But ... there are several more.

For the TCP port see Tim's post.

Solution 3

Assuming that you have control over the execution environment, the listening application could just expose an endpoint using WCF or even a raw TCP socket. That way, any other application can connect to it in a dynamic but structured fashion.

Even though both the sender and receiver are on the same machine, using a network transport solution (like WCF or TCP) is a great way to safely send data across processes.

Here's an example of how to do it in TCP with c#: http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server

WCF can be a bit more complicated (due in part to it's flexibility, and also due to serialization restrictions) but there is plenty of documentation online on how to use it. WCFis a more object-oriented solution because proxy classes can be generated that allow you to make strongly-typed calls to actual objects, versus just sending messages.

Solution 4

To avoid the running of second instance after passing the command line arguments to existing instance, I added below code snippet.

static class Program
{
    [STAThread]

   static void Main(params string[] Arguments)
   {
        Form1 MainForm;
        bool bInstanceFlag;

        Mutex MyApplicationMutex = new Mutex(true, "MyApp_Mutex", out bInstanceFlag);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        if (!bInstanceFlag)
        {
           MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
    }
    else
    {
        MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
        MainForm.Close();
    }
}

public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
    MainForm.AddItem = e.CommandLine[1];
    e.BringToForeground = false;
}

public class SingleInstanceApplication : WindowsFormsApplicationBase
{
    private SingleInstanceApplication()
    {
        base.IsSingleInstance = true;
    }

    public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
    {
        SingleInstanceApplication app = new SingleInstanceApplication();
        app.MainForm = f;
        app.StartupNextInstance += startupHandler;
        app.Run(Environment.GetCommandLineArgs());
    }
}
}

Solution 5

I added some small additions to the previous solution to reference a setter on the form in order to pass the arguments to it.

So first of all, create a static reference to the initial instance of the form (MainForm).

Then, on subsequent sending of arguments, the NewInstanceHandler can use the saved reference to the form to access it's public methods/properties (in my case, a setter called AddItem).

An easy way to test this out is to add a public property to your form with a setter to change the text property of the form (the title text).

[STAThread]
    static Form1 MainForm;

    static void Main(params string[] Arguments)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        MainForm = new Form1();
        SingleInstanceApplication.Run(MainForm, NewInstanceHandler);
    }

    public static void NewInstanceHandler(object sender, StartupNextInstanceEventArgs e)
    {
        MainForm.AddItem = e.CommandLine[1];
        e.BringToForeground = false;
    }

    public class SingleInstanceApplication : WindowsFormsApplicationBase
    {
        private SingleInstanceApplication()
        {
            base.IsSingleInstance = true;
        }

        public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
        {
            SingleInstanceApplication app = new SingleInstanceApplication();
            app.MainForm = f;
            app.StartupNextInstance += startupHandler;
            app.Run(Environment.GetCommandLineArgs());
        }
    } 
Share:
27,023
Kenny
Author by

Kenny

Updated on March 12, 2020

Comments

  • Kenny
    Kenny over 4 years

    I am making an image uploader (upload image to image hosting website) and I'm having some issues passing an argument (image location to an already running application)

    • First of all let's say MyApp.exe is always running
    • Whenever I right click on an image I have added an item in the default windows context menu that says "Upload image".
    • When that's clicked it needs to pass the location to the already running application.

    My program.cs:

    static class Program
    {
        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, UIntPtr
        wParam, IntPtr lParam);
    
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);
    
        [STAThread]
        static void Main(params string[] Arguments)
        {
            if (Arguments.Length > 0)
            {
        //This means that the the upload item in the context menu is clicked
        //Here the method "uploadImage(string location)"
        //of the running application must be ran
            }
            else
            {
        //just start the application
                Application.Run(new ControlPanel());
            }
        }
    }
    

    Note that the ControlPanel class doesn't have a visible form, only a tray icon is present since a form is not needed.

    Could I get any help on how to do this?