.Net CF Single Instance Program
Here is how to limit a .Net Compact Framework program to a single instance of itself. The duplicate instance is simply closed in this case.
I found I needed to use this mutex based code since I was doing a lot of work before calling the Application.Run() method. Once you start to run the application it appears as though Windows Mobile brings the backgrounded application into the foreground.
But for users who mash the enter key 3 or 4 times while not patiently waiting for the device to set up the .Net CF environment to run you will definitly want to use this code.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SomeNameSpace
{
static class SingleInstance
{
[MTAThread]
static void Main()
{
// Check if we have a duplicate instance of the program running
if ( IsInstanceRunning() )
{
// Perhaps log the fact a duplicate program was shut down
return;
}
/*
* Continue with your normal program here
*/
try
{
Application.Run( YourFormClass );
}
catch ( Exception e )
{
// Log an exception that caused the application to close here
MessageBox.Show( "See log file for details.\r\nClosing this application.", "Fatal Application Error" );
}
}
#region OpenNETCF native interface to mutex generation (version 1.4 of the SDF)
public const Int32 NATIVE_ERROR_ALREADY_EXISTS = 183;
#region P/Invoke Commands for Mutexes
[DllImport( "coredll.dll", EntryPoint="CreateMutex", SetLastError=true )]
public static extern IntPtr CreateMutex(
IntPtr lpMutexAttributes,
bool InitialOwner,
string MutexName );
[DllImport( "coredll.dll", EntryPoint="ReleaseMutex", SetLastError=true )]
public static extern bool ReleaseMutex( IntPtr hMutex );
#endregion
public static bool IsInstanceRunning()
{
IntPtr hMutex = CreateMutex( IntPtr.Zero, true, "ApplicationName" );
if ( hMutex == IntPtr.Zero )
throw new ApplicationException( "Failure creating mutex: "
+ Marshal.GetLastWin32Error().ToString( "X" ) );
if ( Marshal.GetLastWin32Error() == NATIVE_ERROR_ALREADY_EXISTS )
return true;
else
return false;
}
#endregion
}
}
December 22nd, 2008 at 10:51 am
Good post!
Any ideas how I can get the application to “restore” if it is already running?
Please email response if I am not subscribed to this thread
Thanks a lot
Chris
December 22nd, 2008 at 12:01 pm
The comments (about 3 down) in this post will answer your question.
http://christian-helle.blogspot.com/2007/06/programmatically-minimize-application.html
Basically the Application.Run(Form) method in the CF checks if the application is already running or not on the system and restores it if it is. I doubt this is the case for Windows Forms – it would likely spawn a new instance on the computer.
Handhelds don’t have the resources to do that – which is why you need to program knowing the system could close your application at any time to claim system resources.
We need to protect the application from attempting to spawn duplicate message pumps with duplicate calls to the Application.Run(Form) method from impatient users before the main message pump can be started. This is in the old .net CF 2.0 framework – I’m not sure if they have fixed it in more recent versions.
February 11th, 2009 at 5:25 am
first great work !
here it goes some code to “restore” window.
//pinvoke stuff ... [DllImport("coredll.dll")] private static extern IntPtr FindWindow(IntPtr className, string windowName); [DllImport("coredll.dll")] internal static extern int SetForegroundWindow(IntPtr hWnd); [DllImport("coredll.dll")] private static extern bool SetWindowPos(IntPtr hwnd, int hwnd2, int x,int y, int cx, int cy, int uFlags);if (IsInstanceRunning()) { // Perhaps log the fact a duplicate program was shut down MessageBox.Show("App. already running!" , "Fatal Application Error"); IntPtr h = FindWindow(IntPtr.Zero, "Form1"); SetForegroundWindow(h); SetWindowPos(h, 0, 0, 0, Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height, 0x0040); return; }May 30th, 2009 at 7:14 pm
Great post Nesser,
I spent a few days trying to get this thing working. Now I don’t even have to write a line of code. CTRL+C -> CTRL+V.
Superb.
Thanks.
July 1st, 2009 at 5:04 am
It is very help full. It resolved my problem.
Thanks for posting such a very good article.
Happy Programming …
February 9th, 2010 at 7:02 pm
Hi all,
All nice code guys! I have another challenge:
I want to use the Form.Hide() method (triggered by an Deactivate event) since it really hides the form so the app can not be closed from the memory or task manager. You probably guessed its behaving like a service :-). I have some code that puts an icon in the task tray and when tapped, it brings back up the form (Form.Show()). This all works fine.
However, I can’t find/think of any code that Show()’s the form after relaunching it from the Start > Programs menu. Does anyone have any idea? Trying mutex detection didn’t work, so I think that NetCF already has a mutex check done before I get to it in the Main() method in program.cs.
Thanks
Arjen
February 10th, 2010 at 2:15 pm
Arjen,
Once you have an instance of your program up and running any time you `Activate` your program from the start menu or an icon the OS brings your application to the foreground. I’m not exactly sure how, but I would assume it is by firing the Activate event and then using a Form.Show().
Read the docs on the (De)activate events. Just allows the OS to demand back resources, etc.
http://www.computerbooksonline.com/content/viewer.asp?a=3179&z=4
The only reason I had to use the mutex check above was because I was doing too much work before letting the OS set up a main form which could be (de)activated and users would click multiple times causing multiple instances of the program. I would consider this a OS bug that needed to be worked around.
Writing a service, or trying to hide your application from the task manager are beyond me on the hand held.
March 26th, 2010 at 1:13 am
Hi,
I am using CF2.0 for developing an application for WM Professional 6.1. I am using
IntPtr FindWindow(IntPtr lpClassName, string lpWindowName)
to get a handle to the application. I am using Pinvoke (coredll.dll , EntryPoint = “FindWindow”) to call this method. The problem i am facing is this method is not responding. It just waits indefenitely. Is there any way to over come this issue?
Thanks in Advance,
Jis.
November 11th, 2010 at 8:33 am
You’re not calling ReleaseMutex in this code, will this not stop your application ever running again until the device is reset?
December 14th, 2010 at 9:52 am
Hi,
for the code above, for the method IsInstanceRunning()
IntPtr hMutex = CreateMutex( IntPtr.Zero, true, “ApplicationName” );
I believe, I have to change “ApplicationName” with the name of my application, right?
Cause I forgot to do so, but it worked fine ! if there already is an instance, it returns. That’s strange, or should I leave “ApplicationName” as it is, as someone earlier said “Copy and Paste”.
I also need a code to put the current running instance in the foreground, as it is hidden behind another running application. Is there a way to do so?
Thanks,
December 14th, 2010 at 10:39 am
About the code that restores the currently running instance, code above:
in the code inside the if statement: if (IsInstanceRunning())
The statement:
IntPtr h = FindWindow(IntPtr.Zero, “Form1″);
What is meant by “Form1″, again should I left it as it is, or change it with the form that run at the program.start(); method?
But I don’t know if the user is currently on this form or any other from inside the application
December 14th, 2010 at 11:02 am
Andy, I’m not sure exactly what you are trying to do.
The original code snippet is used to TERMINATE a duplicate application from being started in the small amount of time that the windows mobile OS is setting up the application. Try not to do a lot of things before calling Application.Run(YourFormClass) with the form your application should show on startup. Read up on that system call.
Once the application is started and running any attempt to start the application again should cause the operating system to bring it to the foreground as it was last seen unless it has been exited by yourself or shutdown by the OS to conserve resources.
I didn’t write the “restore code” – neno did. But look at his pInvoke call and you’ll see that “Form1″ is the string of the form name in your application he is looking to restore – I would suggest using the same form name you use in your Application.Run(YourFormClass) call.
December 15th, 2010 at 7:01 am
Nesser, Thanks a lot for your quick reply,
Here is what I want to do:
I have a main application and I have a -like starter- application, the starter application starts with Windows and it has one form that has a button that starts the main application. The starter application is responsible for preventing the user from accessing the windows common features, the user is allowed to start the main application only.
My problem is:
sometimes the user presses the [Main Application] button on “Start Application” several times, and in most cases the running [Main Application] gets hidden under the “Starter Application”, I applied your code snippet “the original code snipped” to prevent the creation and start of another instance of the [Main Application] when it gets hidden, it works fine, but it doesn’t bring the hidden instance of the [Main Application] from the background. For that reason I used the “restore code” -written by neno” to bring the running instance of the [Main Application] in the front, but it doesn’t work :(
I think the problem is in “Form1″, I don’t want it to restore the first form of the application “the start form”, I just want it to restore the latest opened form, like the normal windows mobile handling scenario.
Thanks,
February 7th, 2011 at 12:58 am
Thanks for your great help :)