Preventing an app from being launched more than once

  • Thread starter Thread starter Mark Rae
  • Start date Start date
Mark said:
Hi,

I'm using the following example for this:
http://www.yoda.arachsys.com/csharp/faq/#one.application.instance

which works perfectly on Vista, but not on XP...

Doesn't throw any errors, but multiple launches of the app are not
prevented.

Is there another solution?

Any assistance gratefully received.

Hi,

Did you see the comment about it being a local mutex? Are you testing
multiple launches of the application within a single user session, or
across user sessions (e.g. terminal services or fast user switching)?

If the latter, you'll need to make the mutex global. If the former, then
it's strange that it doesn't work... Perhaps it's a permissions issue.
 
Did you see the comment about it being a local mutex?
Yes.

Are you testing multiple launches of the application within a single user
session,
Yes.

or across user sessions (e.g. terminal services or fast user switching)?
No.

If the latter, you'll need to make the mutex global.

Indeed, but it still doesn't work on XP either as Local or Global.
If the former, then it's strange that it doesn't work...

I agree. Works perfectly on Vista, though...
Perhaps it's a permissions issue.

I'm logged on to XP as an administrator.
 
Mark said:
Indeed, but it still doesn't work on XP either as Local or Global.


I agree. Works perfectly on Vista, though...


I'm logged on to XP as an administrator.

Hi Mark,

Would you be able to share the code you're using, please?
 
Have not tested this on Vista, but this should work under fx2.0:

internal bool CanStart()
{
Semaphore s = new Semaphore(1, 1,
Assembly.GetExecutingAssembly().GetName().FullName);
if (s.WaitOne(1000, false))
{
// Got ownership.
this.FormClosed += new FormClosedEventHandler(
delegate(object sender, FormClosedEventArgs e)
{
s.Release(); // Capture the local variable in this
closure and release when form closed.
MessageBox.Show("Sem Released.");
});
return true;
}
return false; // Could not get ownership.
}

private void Form1_Load(object sender, EventArgs e)
{
if (!CanStart())
{
MessageBox.Show("Already Started");
this.Close();
return;
}
...
}

--
William Stacey [C# MVP]
PowerLocker, PowerPad
www.powerlocker.com



| Hi,
|
| I'm using the following example for this:
| http://www.yoda.arachsys.com/csharp/faq/#one.application.instance
|
| which works perfectly on Vista, but not on XP...
|
| Doesn't throw any errors, but multiple launches of the app are not
| prevented.
|
| Is there another solution?
|
| Any assistance gratefully received.
|
| --
| http://www.markrae.net
|
 
Mark,

In the end, it is just IL, and you know it will be distributed as part
of the framework. The best code you are going to write is the code you
never have to write or maintain.
 
Mark Rae said:
Hi,

I'm using the following example for this:
http://www.yoda.arachsys.com/csharp/faq/#one.application.instance

which works perfectly on Vista, but not on XP...

Doesn't throw any errors, but multiple launches of the app are not
prevented.

Is there another solution?

Any assistance gratefully received.


Make sure your Mutex doesn't get collected before this program instance
terminates, one way to achieve this is by applying the using idiom like
this:.

....
bool firstInstance;
using (Mutex AppMutex = new Mutex(true, new
Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").ToString(), out firstInstance))
{
if (firstInstance== true)
{
// run your program code from here
}
} // end using scope, mutex released here.
....

where: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is just some valid uuid, but of
course you are free to use anything else to uniquely identify the program.

Willy.
 
Well, that's just a snippet - could you show the whole code, in the
form of a short but complete program?

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

bool blnFirstInstance;
Mutex objMutex = new Mutex(false, "Local\\" + "abcdefg", out
blnFirstInstance);
if (!blnFirstInstance)
{
MessageBox.Show("App is already running", "Single Use Only",
MessageBoxButtons.OK, MessageBoxIcon.Stop);
Application.Exit();
}

// rest of Main() code
}

Works perfectly on 64-bit Vista Business, doesn't work on 32-bit
WinXPPro+SP2 - haven't tried on any other version of Windows...
 
Mark Rae said:
Well, that's just a snippet - could you show the whole code, in the
form of a short but complete program?

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

bool blnFirstInstance;
Mutex objMutex = new Mutex(false, "Local\\" + "abcdefg", out
blnFirstInstance);
if (!blnFirstInstance)
{
MessageBox.Show("App is already running", "Single Use Only",
MessageBoxButtons.OK, MessageBoxIcon.Stop);
Application.Exit();
}

// rest of Main() code
}

Works perfectly on 64-bit Vista Business, doesn't work on 32-bit
WinXPPro+SP2 - haven't tried on any other version of Windows...



Your Mutex instance will get collected whenever the GC comes along for the
first time. Now, probably the GC did not run yet in the first instance
before you started the second instance on 64-bit windows, anyway you need to
protect the mutex instance from premature collection.
My previous reply shows you how you one possibility to prevent this
premature collection.

Willy.
 
Your Mutex instance will get collected whenever the GC comes along for the
first time. Now, probably the GC did not run yet in the first instance
before you started the second instance on 64-bit windows, anyway you need
to protect the mutex instance from premature collection.

I understand what you're saying. However, on 64-bit Vista, this still works
even if I wait a whole hour before trying to run the second instance - maybe
something different happens with Mutexes on Vista and/or 64-bit Windows...?
My previous reply shows you how you one possibility to prevent this
premature collection.

Thanks - I'm looking at that now...
 
Make sure your Mutex doesn't get collected before this program instance
terminates, one way to achieve this is by applying the using idiom like
this:.

...
bool firstInstance;
using (Mutex AppMutex = new Mutex(true, new
Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").ToString(), out
firstInstance))
{
if (firstInstance== true)
{
// run your program code from here
}
} // end using scope, mutex released here.
...

where: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is just some valid uuid, but
of course you are free to use anything else to uniquely identify the
program.

Willy.

Now this is very weird!

I tried your above code, and it worked perfectly on 64-bit Vista but not on
32-bit XP.

However, the version of XP I was testing it on was running in a Virtual PC
2007 virtual machine, so I wondered if that might be the cause, though i
couldn't imagine why...

Therefore, I tried it on XP running on a "real" machine, and it worked
perfectly!

Obviously, I'm happy that it works but I'm not particularly impressed... I
use VPC 2007 all the time for testing my apps, so I wonder what else might
behave differently in this scenario...?

Unfortunately, I don't know enough about mutexes and how they're generated,
but do you have any idea why a virtual machine might cause a mutex to behave
differently from a real machine...?

I'm about to try it on Vista running in a virtual machine, and will let you
know what happens...

I'll also post in the VPC newsgroup to see if anyone has come across this
before...
 
Mark Rae said:
I understand what you're saying. However, on 64-bit Vista, this still
works even if I wait a whole hour before trying to run the second
instance - maybe something different happens with Mutexes on Vista and/or
64-bit Windows...?

Waiting is not enough, you should allocate enough objects for the GC to kick
in (or you could force a GC collect).
Don't forget the the GC threshold for 64-bit .NET applications is quite a
bit larger than for 32-bit processes, so it can take a while before the GC
runs.


Willy.
 
Mark Rae said:
Now this is very weird!

I tried your above code, and it worked perfectly on 64-bit Vista but not
on 32-bit XP.

However, the version of XP I was testing it on was running in a Virtual PC
2007 virtual machine, so I wondered if that might be the cause, though i
couldn't imagine why...

Therefore, I tried it on XP running on a "real" machine, and it worked
perfectly!

Obviously, I'm happy that it works but I'm not particularly impressed... I
use VPC 2007 all the time for testing my apps, so I wonder what else might
behave differently in this scenario...?

Unfortunately, I don't know enough about mutexes and how they're
generated, but do you have any idea why a virtual machine might cause a
mutex to behave differently from a real machine...?

I'm about to try it on Vista running in a virtual machine, and will let
you know what happens...

I'll also post in the VPC newsgroup to see if anyone has come across this
before...


Both should behave the same, unless you are running in different logon
session, in which case you can try using a global named mutex. To do this
you should start the name with "Global\".

Willy.
 
Have you tried my code above?

--
William Stacey [C# MVP]
PowerLocker, PowerPad
www.powerlocker.com



| |
| > Make sure your Mutex doesn't get collected before this program instance
| > terminates, one way to achieve this is by applying the using idiom like
| > this:.
| >
| > ...
| > bool firstInstance;
| > using (Mutex AppMutex = new Mutex(true, new
| > Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").ToString(), out
| > firstInstance))
| > {
| > if (firstInstance== true)
| > {
| > // run your program code from here
| > }
| > } // end using scope, mutex released here.
| > ...
| >
| > where: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is just some valid uuid, but
| > of course you are free to use anything else to uniquely identify the
| > program.
| >
| > Willy.
|
| Now this is very weird!
|
| I tried your above code, and it worked perfectly on 64-bit Vista but not
on
| 32-bit XP.
|
| However, the version of XP I was testing it on was running in a Virtual PC
| 2007 virtual machine, so I wondered if that might be the cause, though i
| couldn't imagine why...
|
| Therefore, I tried it on XP running on a "real" machine, and it worked
| perfectly!
|
| Obviously, I'm happy that it works but I'm not particularly impressed... I
| use VPC 2007 all the time for testing my apps, so I wonder what else might
| behave differently in this scenario...?
|
| Unfortunately, I don't know enough about mutexes and how they're
generated,
| but do you have any idea why a virtual machine might cause a mutex to
behave
| differently from a real machine...?
|
| I'm about to try it on Vista running in a virtual machine, and will let
you
| know what happens...
|
| I'll also post in the VPC newsgroup to see if anyone has come across this
| before...
|
|
| --
| http://www.markrae.net
|
 
You don't need to deal with any of that GC stuff using example I posted,
because the sem is released cleanly on form closed event. You could do same
kind of thing with a mutex.

--
William Stacey [C# MVP]


| |
| > Your Mutex instance will get collected whenever the GC comes along for
the
| > first time. Now, probably the GC did not run yet in the first instance
| > before you started the second instance on 64-bit windows, anyway you
need
| > to protect the mutex instance from premature collection.
|
| I understand what you're saying. However, on 64-bit Vista, this still
works
| even if I wait a whole hour before trying to run the second instance -
maybe
| something different happens with Mutexes on Vista and/or 64-bit
Windows...?
|
| > My previous reply shows you how you one possibility to prevent this
| > premature collection.
|
| Thanks - I'm looking at that now...
|
|
| --
| http://www.markrae.net
|
 
Both should behave the same,

I agree!
unless you are running in different logon session,

I'm not.
in which case you can try using a global named mutex.

I've tried both Local and Global, and also changing the first argument from
false to true...

However, I can further confirm that your code most certainly *does* work on
Vista installed in a virtual machuine...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top