8

I'm having a seriously problem with my little application; basically it's very easy to understand:

My software, when opened, do it's things.

I want to focus to opening another instance (And I mean opening again the .exe) ,check if it's already opened. If not simply start the application but if it's already running (AKA second or more instance) "simply" pass input argument (the args string array)to the first instance, that will processate it adeguately.

Here's my program.cs

static class Program
{
    static Mutex mutex = new Mutex(true, "{blabla}");

    [STAThread]
    static void Main(String[] args)
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            //First Instance!

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

                CALL A MY STATIC METHOD, DO SOME THINGS

                Application.Run(new Form1());
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
        else
        {
            //Not-so-first instance!
            CALL A STATIC METHOD, 
            DO OTHER THINGS LIKE COMUNICATE WITH FIRST INSTANCE

            SIMPLY CLOSE.
        }
    }
}

This will only recognize (with mutex) if it's already opened but (off course) it can't communicate anything to the main instance.

I've tried lot of things but I can't get it work.

I've tried this but I seriously don't understand (after a lot of time wasted) how to put my "first time" code and the "already running" code.

Tried also MSMQ but I can't make it work.

Can someone please help me? It's a basic software that do a very basic things but I've spent day to make it work like I want!

2
  • Your second instance is running in a different process. You'll have to implement some sort of communication mechanism - either MSMQ, serialization over a socket, etc. Making things static isn't going to do it. The fact that you're running multiple copies of the same executable does not make the problem simpler than communicating between different apps.
    – 3Dave
    Commented May 26, 2016 at 14:22
  • Unfortunatelly I learned today that isn't to easy communicate with another program, even if it's the same executable. I understand that different copies must be managed differently than make everything static; The static method I wrote it's inside another .cs file and it's used in my program logic: isn't much relevant to the question:)
    – Alex DG
    Commented May 26, 2016 at 15:42

3 Answers 3

1

One of the simplest ways to communicate would be to send a Windows message from the second instance to the first instance. The second instance would use PostMessage to send the message and the first instance would override the WndProc method of Form1 to handle the message.

There is an example here: Send message to a Windows process (not its main window)

That question also has an answer that uses a pipe (and WCF) for the communication.

There are many forms of interprocess communication. Which one you use depends on your needs, for example Windows Messages can't carry a great deal of information whereas a pipe can stream data at very high speed.

Update A simple alternative could be IPCChannel . This allows you to create an object in the first instance that can be called by the second instance. You can create a method on that object and pass your data as arguments

6
  • I've tried the chitza final solution and it work very well, except one thing: we use PostMessage to send 'input' to the main instance and from there I can manage to launch function or do operations. The problem it's that PostMessage allow only Int parameter; I want to send some kind of structured data (Like an array or an object) but I don't know if it's possible. What do you say? There's something I can try?
    – Alex DG
    Commented May 26, 2016 at 19:24
  • If you need to send more data then you need a more advanced form of Interprocess Communication. MSMQ is one way to go but you seem to be having trouble with that. A simple alternative could be msdn.microsoft.com/en-us/library/… . This allows you to create an object in the first instance that can be called by the second instance. You can create a method on that object and pass your data as arguments
    – David J
    Commented May 27, 2016 at 9:21
  • THANKS! That has solved my problems! I had some other little minor issues (I can't call everything from the second instance: some things don't work very well, at least in my case, like FolderBrowserDialog and inside some deep method calling some methods throw an exception (Visual Studio Debugger also has told me that can't be called from outside) but THIS has solved my problem. So I've combined IpcChannel the InteropMessage (Chitza solution) and now I can do basically anything I want! You made my day, and my software :)
    – Alex DG
    Commented May 27, 2016 at 17:35
  • Great stuff. I'm glad it helped you out. I've added the IPC channel to my answer. Please accept it if it solved your problem.
    – David J
    Commented May 28, 2016 at 21:47
  • Sorry If I'm reply late but I have a problem that....I've created myself. In the main instance I listen for message in WndProc. In the second instance I send the message, that 'trigger' the WndProc method in main instance. All worked good until I've installed this link. To install this I had to rename my main form method declaration from 'public partial class Form1 : Form' to 'public partial class Form1 : MetroFramework.Forms.MetroForm' . Doing THAT IPC simply doesn't catched anymore in first instance. Can you give me some advice why?
    – Alex DG
    Commented May 30, 2016 at 16:05
-1

Use Mutex.

    // Generate your GUID and put it here
    private const string ProgramRunningGuid = "BD2023EE-F7B3-47B8-8C76-32668196E4D3";
    private Mutex _mutex;

    private bool IsProgramRunning()
    {
        bool createdNew;
        // It returns a bool value determining if a Mutex that created is new
        // If the program is already running mutex wouldn't be new
        _mutex = new Mutex(true, ProgramRunningGuid, out createdNew);
        return !createdNew;
    }

On program exit you need to release the mutex:

    _needlesRunningMutex.ReleaseMutex();

And if you want to focus the already running instance of your application you can check my answer with working solution here: https://stackoverflow.com/a/35018042/3731444

If you just need to share some bool arguments to determine if things are turned on or off you can use Mutexes for each of them either.

If you need to pass parameters to your .exe when you're starting it check this question: How to pass parameters to an exe?

If you need to make a continious communication between two instances of your running apps keep it up with MSMQ. I'll try to help you if any questions.

Check a how to use MSMQ here: https://github.com/IvanYurchenko/MSMQSample

8
  • 1
    But this wouldn't resolve my main problem: make an instance of my software communicate with the main one. With your solution I can understand if it's already started, but I've already done it in my code. Or I don't understand your solution?
    – Alex DG
    Commented May 26, 2016 at 14:15
  • Added an update to an answer. Let me know if it's still unclear. Commented May 26, 2016 at 14:19
  • I'm a very beginner to MSMQ (and maybe to C# in general). I don't need a constant communication between 'original instance' and the others one. I only need that the new instance send a message to the main instance and then they simply close. I'm reading the code but I don't understand some new concept: I have included reference to System.Messaging in my project but I don't understand WHERE to put "receiver message logic" in my Form.cs file to costant 'scan' incoming message. Also variables MessageAddress/QueueName can be anything I want? Can I transfer only a String array?
    – Alex DG
    Commented May 26, 2016 at 15:59
  • I've created a sample project for you that uses MSMQ. You will need to add reference to the System.Messaging for your project via Add Reference menu. Also make sure that MSMQ system is installed for you (Programs and features - Turn Windows features on or off - Microsoft Message Queue (MSMQ) Server) Commented May 26, 2016 at 17:08
  • Thanks :) I didn't thought that MSMQ should be enabled from Programs and Features. Once enabled all started to work like a sharm :) Unfortunatelly not on all pc it's enabled by default and I've tried a more "easy" way. But for sure I will use on other project, thanks a lot :)
    – Alex DG
    Commented May 27, 2016 at 17:27
-1

I pass the arguments through a text file (I'm sure you can translate from VB.NET/pseudocode):

Private _uniqueEventName As String
Private _uniqueMutexName As String
Private _eventWaitHandle As EventWaitHandle
Private _mutex As Mutex

Private Sub ensureSingleInstance()
    _uniqueEventName = "{0ae64101-e630-4221-bf10-123fdddd5ab2}" + Assembly.GetEntryAssembly().GetName().Name
    _uniqueMutexName = "{03169a07-793b-48c6-8ceb-1232388cb69a}" + Assembly.GetEntryAssembly().GetName().Name

    Dim isOwned As Boolean
    _mutex = New Mutex(True, _uniqueMutexName, isOwned)
    _eventWaitHandle = New EventWaitHandle(False, EventResetMode.AutoReset, _uniqueEventName)

    GC.KeepAlive(_mutex)

    If isOwned Then
        Dim thread As Thread = New Thread(
                               Sub()
                                   While _eventWaitHandle.WaitOne()
                                       Application.Dispatcher.BeginInvoke(
                                           Sub()
                                               ' ****************************************************
                                               ' READ AND PROCESS THE ARGUMENTS FROM C:\MYAPPARGS.TXT
                                               ' ****************************************************

                                               If Not Application.MainWindow Is Nothing Then
                                                   _loggingDAL.Log("Activating main window")

                                                   If (Application.MainWindow.WindowState = WindowState.Minimized Or Application.MainWindow.Visibility = Visibility.Hidden) Then
                                                       Application.MainWindow.Show()
                                                       Application.MainWindow.WindowState = WindowState.Normal
                                                   End If

                                                   Application.MainWindow.Activate()
                                                   Dim topMost As Boolean = Application.MainWindow.Topmost
                                                   Application.MainWindow.Topmost = True
                                                   Application.MainWindow.Topmost = topMost
                                                   Application.MainWindow.Focus()
                                               End If
                                           End Sub)
                                   End While
                               End Sub)
        thread.IsBackground = True
        thread.Start()
    Else
        _loggingDAL.Log("There is already an instance running -> switching and quitting")

        ' ***************************************
        ' WRITE THE ARGUMENTS TO C:\MYAPPARGS.TXT
        ' ***************************************

        _eventWaitHandle.Set()
        Application.Shutdown()
    End If
End Sub

Not the answer you're looking for? Browse other questions tagged or ask your own question.