Passing argument to another instance of the same application
Asked Answered
D

3

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!

Daviddavida answered 26/5, 2016 at 13:45 Comment(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.Meneses
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:)Daviddavida
S
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

Slipknot answered 26/5, 2016 at 14:23 Comment(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?Daviddavida
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 argumentsSlipknot
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 :)Daviddavida
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.Slipknot
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?Daviddavida
Sorry, I'm not familiar with that library. There could be many reasons why it doesn't work. I think that would be a separate question.Slipknot
E
-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://mcmap.net/q/515390/-restore-a-minimized-window-of-another-application

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

Eugenie answered 26/5, 2016 at 14:10 Comment(8)
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?Daviddavida
Added an update to an answer. Let me know if it's still unclear.Eugenie
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?Daviddavida
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)Eugenie
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 :)Daviddavida
You're welcome. ;) Also, there is a way to enable MSMQ from code or include it as a prerequisite in your application so you can do this for user if you're worried that he would have to do it by himself.Eugenie
For the last thing: I'm really interested how I can do that :)Daviddavida
There's an answer here: #683011 Currently, I'm enabling MSMQ programmatically just when the user needs it so I'm using a different approach. Looks like people recommend to install it along with the app so you can try it (maybe I'll make it working such way someday too)Eugenie
C
-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
Cartogram answered 16/12, 2019 at 12:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.