.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
	}
}

15 Responses to “.Net CF Single Instance Program”

  1. Chris Says:

    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

  2. Nesser Says:

    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.

  3. neno Says:

    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;
                }
  4. Minal Says:

    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.

  5. Jitendra kumar Says:

    It is very help full. It resolved my problem.

    Thanks for posting such a very good article.

    Happy Programming …

  6. Arjen d'Ailly Says:

    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

  7. Nesser Says:

    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.

  8. jis Says:

    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.

  9. Paul Says:

    You’re not calling ReleaseMutex in this code, will this not stop your application ever running again until the device is reset?

  10. Andy Harvey Says:

    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,

  11. Andy Harvey Says:

    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

  12. Nesser Says:

    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.

  13. Andy Harvey Says:

    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,

  14. RHMK Says:

    Thanks for your great help :)

  15. Wayne Phipps Says:

    Rather than looking for an error that indicates the Event Already Exists, I prefer the approach detailed here:

    http://msdn.microsoft.com/en-us/netframework/bb943002.aspx

    Hope this helps others.

Leave a Reply