1

I'm currently working on a simple converter tool and was wondering if it's possible to make the application close if I run the .exe again. Some kind of "if two instances run -> close both".

I need this function because I run the application via a shortcut-button inside a third party program. So I would like if my converter app closes once I press this shortcut-button again.

I know it sounds counter intuitive running the exe again to close, but i have to have my app work the same way as the integrated tools in the third party program, and this involves opening and closing tools by pressing their respective toggle-buttons. I can't add a plug-in running inside the third party program, but i CAN add a shortcut button next to the integrated tools. It's a work around, but it will at least act like a toggle button.

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
  • 1
    Seems like the simpler approach is for the second instance to detect that the first is running and close itself before it displays anything. Rather than have the second instance close the first instance, or have the first instance keep checking for other instances in a thread. – David Mar 21 '17 at 21:20
  • @FastAl: If the answer (and the underlying issue) is significantly different from the linked question then I may be able to re-open (not sure if I can do it with one vote). – David Mar 21 '17 at 21:25
  • It's not duplicate to the other question as the code in there, only prevents from opening multiple instances. It doesn't close all of them.. – Morten Bøttcher Nørgaard Mar 21 '17 at 21:28
  • @David You can; hammers can reopen dupes with a single vote also (and edit them if you find a better duplicate) – BradleyDotNET Mar 21 '17 at 21:28
  • @MortenBøttcherNørgaard Similar code though, if the second instance detects the first is running it could close the first one before killing itself. Seems like odd behavior though. – BradleyDotNET Mar 21 '17 at 21:29
  • 1
    if you prevent having multiple instances, then there wouldn't any multiple instances to close when opening a second one – Gonzalo.- Mar 21 '17 at 21:29
  • @Gonzalo.- That's not the purpose. What i wanna achieve is opening and closing my application by running the .exe. Run the exe -> starts the app. Run the exe again -> closes the app – Morten Bøttcher Nørgaard Mar 21 '17 at 21:32
  • 3
    @MortenBøttcherNørgaard: That's... A very unexpected user experience. – David Mar 21 '17 at 21:33
  • I agree with david. Having said that, you could use this http://stackoverflow.com/questions/3768083/closing-one-application-from-another-in-c-sharp-net just it happens that the process you're searching for is the same as the current one you're opening. You might need to tweak something because of that - not sure though – Gonzalo.- Mar 21 '17 at 21:34
  • @BradleyDotNET Yeah, that sounds like a solution, but how does the second instance differentiate between the first and the second? .-S – Morten Bøttcher Nørgaard Mar 21 '17 at 21:35
  • @FastAI Note that answers need to be posted as answers; and its odd to put a VB solution to a C# question. To your second question, it could check for a different process ID, among other possibilities – BradleyDotNET Mar 21 '17 at 21:37
  • @bradleyDotNet - put as answer, will convert to c#... – FastAl Mar 21 '17 at 21:43
  • @david - thanks for opening this back up, I moved my edit to an answer ... you have my respect for sure here! – FastAl Mar 21 '17 at 21:44
  • @David edited my answer... – FastAl Mar 21 '17 at 21:54
  • @David - I know it sounds counter intuitive running the exe again to close, but i have to have my app work the same way as the integrated tools in the third party program, and this involves opening and closing tools by pressing their respective toggle-buttons. I can't add a plug-in running inside the third party program, but i CAN add a shortcut button next to the integrated tools. It's a work around, but it will at least act like a toggle button. :-) – Morten Bøttcher Nørgaard Mar 21 '17 at 21:55

2 Answers2

1

Step 1 Identify a 2nd instance:

I'd recommend the MUTEX answer in this question: How can I prevent launching my app multiple times?

Step 2 Get that first instance closed

Although the MUTEX answer identifies a second instance, it gives no way to find it and tell it to close.

Solution: Listen with a named pipe in the app (first instance the ClosEE):

//using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;

public static class SomeClass
{

    public static void SomeMethod()
    {
        Threading.Thread t = new Threading.Thread(() =>
        {
            try {
                while (true) {
                    dynamic server = new NamedPipeServerStream("Closer", PipeDirection.InOut, -1);
                    server.WaitForConnection();
                    if (!server.IsConnected)
                        return;
                    dynamic reader = new IO.StreamReader(server);
                    dynamic casetxt = reader.ReadToEnd();
                    server.Close();
                    RootForm.Invoke(() =>
                    {
                        if (casetxt == "End") {
                            System.Environment.Exit(0);
                        }
                    });
                }
            } catch (Exception ex) {
                // try/catch required in all child threads as error silently ends app.
                // log it... 
            }
        });
        t.IsBackground = true;
        t.Name = "EnderListener";
        t.Start();
    }
}

//=======================================================
//Service provided by Telerik (www.telerik.com)

Then when you detect a second instance via the Mutex, send this message from the 2nd instance the "Closer":

    dynamic serverloopcount = 1;
    dynamic iteration = 1;
    dynamic GotServerCount = false;
    do {
        NamedPipeClientStream client = new NamedPipeClientStream("Closer");
        client.Connect();
        if (!GotServerCount) {
            GotServerCount = true;
            serverloopcount = client.NumberOfServerInstances;
        }
        dynamic reader = new IO.StreamReader(client);
        dynamic writer = new IO.StreamWriter(client);
        writer.WriteLine("End");
        writer.Flush();
        writer.Close();
        client.Close();
        iteration += 1;
    } while (iteration <= serverloopcount);

Good luck.

Community
  • 1
  • 1
FastAl
  • 6,194
  • 2
  • 36
  • 60
  • Is there a reason you used `dynamic` instead of `var` or proper type? – Logman Apr 19 '17 at 09:07
  • @logman - This code was originally in VB and used type infer (just Dim instead of var). I didn't convert it by hand though I used Telerik's converter web page. It used Dynamic. I would have thought var would have been fine. So that is the reason! – FastAl Apr 19 '17 at 21:49
1

You could do something like this:

Process currentProcess = Process.GetCurrentProcess();
bool suocide = false;
foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
{
    if (process.MainModule.FileName == currentProcess.MainModule.FileName && process.Id != currentProcess.Id)
    {
        process.CloseMainWindow();
        process.Close();
        //process.Kill(); or you can do kill instead
        suocide = true;
    }
}

if (suocide)
    currentProcess.Kill(); // you probably don't care about new process as it is just for closing purpose but if you do then do a proper application exit

You can put it inside your window constructor.

Logman
  • 4,031
  • 1
  • 23
  • 35