Thursday, February 24, 2005

A better way to check whether another instance of your application is already running

Do you needed to restrict your C# Win Forms application to a single instance? - I did.

And what do you do these days when you need to create a piece of code? Right, you're opening Google and typing something like "C# single instance application".

Wow - big bunch of answers right at your service. And all looks pretty similar (how could? :0) ) - thanks to our day’s information plague.

But even if there is too much information – there is never too much knowledge, right?

So, putting aside all mine pathetic – what do we have?

All solutions I've found are offering to check whether a process with the same name already exists:

http://weblogs.asp.net/tgraham/archive/2004/05/28/143907.aspx

http://www.dotnet247.com/247reference/msgs/11/56519.aspx

private static bool ExistsPreviousInstance()
{
System.String myProcessName =
System.Diagnostics.Process.GetCurrentProcess().ProcessName;
return System.Diagnostics.Process.GetProcessesByName( myProcessName ).Length > 1;
}

This worked like a charm on my developer computer, but when we started to test my application on other machines – zbang – on SOME computers System.InvalidOperationException computers was thrown from System.Diagnostics.Process.GetCurrentProcess().

I’ve spent quite a while, trying to understand what makes those few computers so different and finally – the problem is that they have performance counters disabled!
Go to
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfProc\Performance,
change it from 0 to 1 and it works like a charm again.
(Thanks to
http://blogs.pingpoet.com/overflow/archive/2004/07/27/673.aspx ).

But do you really want to deal with registry here? Do you want to deal with adding security permissions to be able to access System.Diagnostics.Process stuff?

If not – plain old named mutex solution seems to be a better way:

private
static bool ExistsPreviousInstance()
{
bool
mutexWasCreated=false;
_existanceCheckMutex = new System.Threading.Mutex( false, "MyFirm.MyApplication", out mutexWasCreated );
return mutexWasCreated==false;
} private static System.Threading.Mutex _existanceCheckMutex;

So easy? Misfortunately - we are not done yet.
What if by occasion you running your application from different user accounts? For example, one - from SYSTEM and the second one - from ADMINISTRATOR? It happens that above simple solution wouldn't work. All because you need to set such security attributes for our named mutex that they would enable to 'query' it from different accounts. In my case - I've run in to that problem, since my application is executed by 3rd party scheduler, which is a system service (SYSTEM), while I want to prevent user from running occasionally it's 2nd instance from, say, ADMINISTRATOR account. If you are not involved in such a weird situation you're done with the above code.

Otherwise - you have two choises:

  1. Check that you getting ApplicationException and the problem is "Access denied":
    exception.Message == "Access is denied.\r\n"
  2. Use the following sniplet, using PINVOKE'd WIN32 API calls (I didn't found any way to do it directly through the .NET 1.1 API. Any one did? Is there any way at all to manipulate ACE's SID's, DACL's in it? Btw, there is an API to set security attributes directly in mutex constructor in WinFX).

{{{To be continued}}}.

Hope it could keep a pellet of Advil Liqui-gel for some one.

My first blog posting ...




Well, friends, I guess my blog-time has come and this is my first blog posting.
Not sure yet how far I will come that way, whether it would be mine permanent host, etc.
For a while I'm going to start with few development issues I want to share.