Single instance of app

527 views
Skip to first unread message

Steve Barnett

unread,
Nov 3, 2005, 5:37:11 AM11/3/05
to
I want to ensure that there is only ever one instance of my app running on a
single PC at any time. I understand that I can achieve this by using a mutex
and, if I can't take ownership of the mutex, I know there is another
instance of my program running.

Problem is, how do I get the "new" instance to communicate with the "old"
instance? The new one will have been started with a command line parameter
that I want to pass to the old instance for execution. In my VB6 days, I did
this using DDE (old, but safe).

What's the C# equivalent?

Can you point me at the classes I might need to work with please (No
detailed code, please - I'm trying to learn this stuff for myself).

Thanks
Steve


Jérôme Bonnet

unread,
Nov 3, 2005, 6:15:29 AM11/3/05
to
Hi,
 
it's quite simple thanks to .net framework which provides everything you need ;-)
 

                                        using

System.Diagnostics;
public static bool IsOneInstance()
  {
   Process pcur = Process.GetCurrentProcess();
   Process[] ps = Process.GetProcesses();
   foreach( Process p in ps )
   {
    if ( pcur.Id  != p.Id )
     if ( pcur.ProcessName == p.ProcessName )
      return false;
          
   }
   return true;
  }
Jey
 
 
"Steve Barnett" <non...@nodomain.com> a écrit dans le message de news: %23AMlOKG...@TK2MSFTNGP12.phx.gbl...

Steve Barnett

unread,
Nov 3, 2005, 7:00:00 AM11/3/05
to
Thank you
Steve
"Jérôme Bonnet" <jbo...@topsys.fr> wrote in message news:4369f154$0$17217$8fcf...@news.wanadoo.fr...

Peter Kirk

unread,
Nov 3, 2005, 8:01:03 AM11/3/05
to

"Jérôme Bonnet" <jbo...@topsys.fr> skrev i en meddelelse
news:4369f154$0$17217$8fcf...@news.wanadoo.fr...

> using System.Diagnostics;
>public static bool IsOneInstance()
> {
> Process pcur = Process.GetCurrentProcess();
> Process[] ps = Process.GetProcesses();
> foreach( Process p in ps )
> {
> if ( pcur.Id != p.Id )
> if ( pcur.ProcessName == p.ProcessName )
> return false;
>
> }
> return true;
> }

Would it be possible for two of your processes to start almost
simultaneously, detect each other, return false from this method - and
therefore both terminate?


Nicholas Paldino [.NET/C# MVP]

unread,
Nov 3, 2005, 8:34:30 AM11/3/05
to
    Unfortunately, this is a incredibly inefficient way of doing this, and not accurate, either.
 
    If you are using .NET 2.0, derive a class from the WindowsFormsApplicationBase class in the Microsoft.VisualBasic.ApplicationServices namespace (in Microsoft.VisualBasic.dll).  There is a protected property in that class named IsSingleInstance.  Set it to true in your derived class (in the constructor).
 
    Then, you can call the Run method on your derived class like you would call the Run method on the Application class.  It will then run your program.
 
    Additionally, you can sign up for the StartupNextInstance event (or override your OnStartupNextInstance method in your derived class).  This is called when another instance of your app is started.  The event, however, fires in the instance that is already running.  The WindowsFormsApplicationBase takes care of the interprocess communication for you.
 
    If you are not using .NET 2.0, you should use a Mutex with a unique name (I find that the assembly qualified type name is a good unique name) and try and get access to it.  If you can not, then you know that another instance of your app is running.
 
    If you want the first app to know the second app was started up (unsuccessfully), then you will have to create an interprocess communication mechanism (such as remoting, which is what WindowsFormsApplicationBase uses, but it uses the new IPC channel, which uses named pipes, which is more efficient than the TCP or HTTP channels) to communicate that information to the original application.
 
    Hope this helps.
 

--
          - Nicholas Paldino [.NET/C# MVP]
          - m...@spam.guard.caspershouse.com
"Jérôme Bonnet" <jbo...@topsys.fr> wrote in message news:4369f154$0$17217$8fcf...@news.wanadoo.fr...

Steve Barnett

unread,
Nov 3, 2005, 8:44:20 AM11/3/05
to
That's great, thank you.

For no rational reason, I think I'll go for the mutex/IPC route. I believe I'll get more learning out of that and I won't have to admit that VB users have something that C# users need!

Steve
"Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote in message news:e5niRtH4...@TK2MSFTNGP10.phx.gbl...

Steve Barnett

unread,
Nov 3, 2005, 8:46:31 AM11/3/05
to

"Peter Kirk" <p...@alpha-solutions.dk> wrote in message
news:e3SPmaH...@TK2MSFTNGP15.phx.gbl...

This is why I want to go with a Mutex, as it should take care of this
situation. In reality, it's unlikely that a user could start two copies that
fast - they'll typically be double clicking on files in Explorer. I just
never imagined it would get so complicated - I did this in a couple of lines
of ode in VB6.

Steve


Ignacio Machin ( .NET/ C# MVP )

unread,
Nov 3, 2005, 8:58:08 AM11/3/05
to
Hi,

Use a mutex:

http://www.yoda.arachsys.com/csharp/faq/#one.application.instance


cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

"Steve Barnett" <non...@nodomain.com> wrote in message
news:%23AMlOKG...@TK2MSFTNGP12.phx.gbl...

Steve Barnett

unread,
Nov 3, 2005, 9:37:21 AM11/3/05
to
I've been trying to do this all afternoon. The code looks Ok and I'm getting
a single instance of my app started, but I'm also getting an "Abandoned
Mutex Exception" generated when my app closes. I've had a look on
CodeProject.Com and it appears that this is probably a problem with the .Net
2.0 Beta 2.

Maybe looking at process id's is safer after all. I'm not desperate for
red-hot performance.

Steve


"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote
in message news:%23stWg6H...@TK2MSFTNGP09.phx.gbl...

Ignacio Machin ( .NET/ C# MVP )

unread,
Nov 3, 2005, 10:00:12 AM11/3/05
to
Hi,

Are you releasing the mutex when you close your app? using ReleaseMutex ?

Also, I would guess it implement IDisposable, so you better call Dispose
too.

cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

"Steve Barnett" <non...@nodomain.com> wrote in message

news:%23F9GcQI...@TK2MSFTNGP09.phx.gbl...

Steve Barnett

unread,
Nov 3, 2005, 10:19:10 AM11/3/05
to
My code runs in the Main() function, before the main form is created, so I
would expect the I didn't need a Dispose() override (I could be totally
wrong - this is a learning exercise).

static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
bool FirstInstance = false;
Mutex AppMutex = new Mutex(true, "IPM_Licence_Editor", out
FirstInstance);

if (FirstInstance == true)
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
}
}

Other variant's I've tried include maning the Mutex a static variable and
including an AppMutex.ReleaseMutex() after the Application.Run.

What actually happens is that every tmie I click on my app (after the first
instance), a new instance is created and it appears to hang at the creation
of the Mutex. I can see them listed in TaskManager. When I close the one
"running" copy, I get the AbandonedMutex exception and all instances close.

Steve

"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote

in message news:%23r52LdI...@TK2MSFTNGP15.phx.gbl...

Willy Denoyette [MVP]

unread,
Nov 3, 2005, 11:05:24 AM11/3/05
to
A Mutex holds an OS handle and implemnts IDisposable, so you need to Dispose
of the instance, the easiest to do is by means of a using block like
this....

...
using(Mutex AppMutex = new Mutex(true, "IPM_Licence_Editor", out
FirstInstance))
{
if (FirstInstance == true)
{
...

}// end of using block, AppMutex will be disposed and its handle freed.


Willy.


"Steve Barnett" <non...@nodomain.com> wrote in message

news:OCtFznI...@tk2msftngp13.phx.gbl...

Steve Barnett

unread,
Nov 3, 2005, 11:51:53 AM11/3/05
to
Got you. It still doesn't work, but now I understand where you're coming
from. The code I have ended up with is:

static void Main()
{
bool FirstInstance = false;

using (Mutex AppMutex = new Mutex(true, "IPM_Licence_Editor", out

FirstInstance))
{
if (FirstInstance == true)
{

Application.EnableVisualStyles();
Application.Run(new MainForm());
}
} // Mutex will be disposed of here
}

Which should work, I believe. However, I still have the problem that
multiple apps get started and sit there waiting for the first version to
end. When it does, all of the ones queued up fail with the Abandoned Mutex
Exception.

This isn't critical to my app right now, so I guess I'd better come round it
again when I've moved on from the Beta2 libraries.

Thanks, everyone, for the help.
Steve


"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:OLJ06AJ4...@TK2MSFTNGP15.phx.gbl...

Ignacio Machin ( .NET/ C# MVP )

unread,
Nov 3, 2005, 1:59:55 PM11/3/05
to
Hi,

You have to pass false to the first parameter ( it's correctly in the link
I gave you)

from msdn:
If name is not a null reference (Nothing in Visual Basic) and initiallyOwned
is true, then the application must ensure that a mutex that has the same
name and is owned by the calling thread does not already exist. If the mutex
is being used for cross-process communication, you should set initiallyOwned
to false, or use the Mutex(Boolean, String, Boolean) constructor. Otherwise,
it will be difficult to determine which process has initial ownership.

If you pass true the mutex will wait until it adquire it. This is not what
you want !
You have no use for the mutex, you only needs to know if the mutex exist
(indicating another instance) or not.

new Mutex(false, "Local\\"+someUniqueName, out firstInstance);

is the correct set of parameters.


cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

"Steve Barnett" <non...@nodomain.com> wrote in message

news:OX6NnbJ4...@TK2MSFTNGP15.phx.gbl...

Steve Barnett

unread,
Nov 4, 2005, 3:46:08 AM11/4/05
to
Thanks, that's working now. I took the "true" from Willy's post - by then
I'd got so frustrated I wasn't reading the documentation any more.

Well, that's the easy bit over, now I need to make my new instance talk to
the old instance.

Oh joy!

Thanks for all the help.
Steve


"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote

in message news:echNKjK4...@TK2MSFTNGP15.phx.gbl...

Willy Denoyette [MVP]

unread,
Nov 4, 2005, 5:36:34 AM11/4/05
to

"Steve Barnett" <non...@nodomain.com> wrote in message
news:uJOa1wR4...@TK2MSFTNGP12.phx.gbl...

> Thanks, that's working now. I took the "true" from Willy's post - by then
Which I took from your's ;-)
....
and did not pay attention to it, I just wanted to show you the wrapping in a
using block.

Willy.


Steve Barnett

unread,
Nov 4, 2005, 8:02:35 AM11/4/05
to
I paid intense attention to the code you posted... too intense <bg>

It wasn't meant as a criticism of you. I do appreciate the help you and the
others offered.

Steve

"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message

news:%239PmztS...@TK2MSFTNGP10.phx.gbl...

Maruthi

unread,
Nov 6, 2005, 1:48:02 AM11/6/05
to
In good old VB6 one line of code would do:


If App.PrevInstance Then End

Steve Barnett

unread,
Nov 7, 2005, 4:10:13 AM11/7/05
to
I know... and half a dozen lines of DDE code would have transferred my
command line parameter to the running application and I would have achieved
something useful in the last three days. Unfortunately, the world has moved
on (without me, so far) and I'm trying to catch up with the more productive
world of C#.

I now know it ain't gonna be as easy as the hipe promised. Still, if it was
that easy, everyone would be doing it.

Steve

"Maruthi" <Mar...@discussions.microsoft.com> wrote in message
news:5DFED991-6BCB-498F...@microsoft.com...

Reply all
Reply to author
Forward
0 new messages