1

Application c:\pinkPanther.exe is running and it is application i wrote in c#. Some other application starts c:\pinkPanther.exe purpleAligator greenGazelle OrangeOrangutan and i would like not to start new instance of c:\pinkPanther.exe with these arguments, but to currently running c:\pinkPanther.exe register it and react to it somehow.

How to do it?

EDIT!!!: i'm very sorry about pinkPanther.exe and ruzovyJeliman.exe that caused the confusion - i translated question from my native language and missed it :(

evlo
  • 401
  • 1
  • 4
  • 8
  • I edited the question, hope that it is more clear now. – evlo Jul 02 '11 at 20:28
  • Did you mean to call pinkPanther.exe in the example too? – svick Jul 02 '11 at 20:29
  • @evlo: No, still not very clear. What is the relation between those 2 .EXEs ? And what does "register it" mean? – H H Jul 02 '11 at 20:30
  • @evlo, it's not clear still; you are actually invoking two different app. Do you mean, when you execute 'c:\ruzovyJeliman.exe ....' instead 'c:\pinkPanther.exe' kicks off. – Rahul Jul 02 '11 at 20:31
  • So the situation if I'm understanding it correctly, is that there are two different programs which can't be running at the same time with the same arguments. Is this correct? – Chris Eberle Jul 02 '11 at 20:32
  • i accidentally the whole question? – Jesus Ramos Jul 02 '11 at 20:34
  • Ok, i deluge torrent client can run exe with parameters of torrent name and path after it finish downloading torrent. Since it can finish 10 torrents in a short time exacting all at a same time cause HDD IO spam and then it is very slow, so i'm trying to crate reliable application that would queue these About pinkPanther.exe and ruzovyJeliman.exe that caused the confusion - i translated question from my native language and missed it :( – evlo Jul 02 '11 at 20:36

2 Answers2

2

This is assuming your application is a WinForms app, as that will make it easier to keep it open. This is a very simple example, but it will show you the basics:

  1. Add a reference to Microsoft.VisualBasic.
  2. Create an Application class inheriting from WindowsFormsApplicationBase. This base class contains built-in mechanisms for creating a single-instance application and responding to repeated calls on the commandline with new arguments:

    using Microsoft.VisualBasic.ApplicationServices;
    
    //omitted namespace
    public class MyApp : WindowsFormsApplicationBase {
        private static MyApp _myapp;
    
        public static void Run( Form startupform ) {
            _myapp = new MyApp( startupform );
    
            _myapp.StartupNextInstance += new Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventHandler( _myapp_StartupNextInstance );
    
            _myapp.Run( Environment.GetCommandLineArgs() );
        }
    
        static void _myapp_StartupNextInstance( object sender, Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e ) {
            //e.CommandLine contains the new commandline arguments
            // this is where you do what you want with the new commandline arguments
    
            // if you want it the window to come to the front:
            e.BringToForeground = true;
        }
    
        private MyApp( Form mainform ) {
            this.IsSingleInstance = true;
            this.MainForm = mainform;
        }
    }
    
  3. All you have to change in Main() is call Run() on your new class rather than Application.Run():

    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault( false );
            MyApp.Run( new MyMainForm() );
        }
    }
    

WindowsFormsApplicationBase has some other capabilities you can explore, as well.

Joel B Fant
  • 24,406
  • 4
  • 66
  • 67
  • Thank you for example. I use WPF, but i guess i can make winforms wraper to show WPF window. What is MyMainForm() in your example? I tried MyApp.Run(new Form1()); and that did not work - form is not shown on first start even tough InitializeComponent(); is called. With standard Application.Run(new Form1()); it is shown. – evlo Jul 03 '11 at 12:19
  • That you are using WPF is exactly the kind of information you should provide in your questions. This would not work as-is (and maybe not at all) with WPF. – Joel B Fant Jul 03 '11 at 15:50
  • Sorry, I see what you mean now. I forgot `_myapp.Run()`. – Joel B Fant Jul 03 '11 at 17:43
1

To communicate with the other instance of the application, you need some sort of inter-process communication. Apparently, WCF is the recommended form of IPC in .Net. You can do that with code like this (using WPF, but WinForms would be similar):

[ServiceContract]
public interface ISingletonProgram
{
    [OperationContract]
    void CallWithArguments(string[] args);
}

class SingletonProgram : ISingletonProgram
{
    public void CallWithArguments(string[] args)
    {
        // handle the arguments somehow
    }
}

public partial class App : Application
{
    private readonly Mutex m_mutex;
    private ServiceHost m_serviceHost;
    private static string EndpointUri =
        "net.pipe://localhost/RuzovyJeliman/singletonProgram";

    public App()
    {
        // find out whether other instance exists
        bool createdNew;
        m_mutex = new Mutex(true, "RůžovýJeliman", out createdNew);

        if (!createdNew)
        {
            // other instance exists, call it and exit
            CallService();
            Shutdown();
            return;
        }

        // other instance does not exist
        // start the service to accept calls and show UI
        StartService();

        // show the main window here
        // you can also process this instance's command line arguments
    }

    private static void CallService()
    {
        var factory = new ChannelFactory<ISingletonProgram>(
            new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), EndpointUri);

        var singletonProgram = factory.CreateChannel();
        singletonProgram.CallWithArguments(Environment.GetCommandLineArgs());
    }

    private void StartService()
    {
        m_serviceHost = new ServiceHost(typeof(SingletonProgram));
        m_serviceHost.AddServiceEndpoint(
            typeof(ISingletonProgram),
            new NetNamedPipeBinding(NetNamedPipeSecurityMode.None),
            EndpointUri);

        m_serviceHost.Open();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        if (m_serviceHost != null)
            m_serviceHost.Close();

        m_mutex.Dispose();
        base.OnExit(e);
    }
}
Community
  • 1
  • 1
svick
  • 236,525
  • 50
  • 385
  • 514