Home .NET Windows mobile: one instance of the app

Windows mobile: one instance of the app

by admin

Problem

Working on a windows mobile project (Visual Studio 2008, .net cf 3.5, C#) I encountered a problem with controlling how one instance of an application is run. Unfortunately, the creators of .net compact framework 3.5 (and earlier versions) didn’t include the ability to search for a process by its name – the method System.Diagnostics.Process GetProcessesByName() . No additional methods were found that would help to solve the problem with managed code.

Solution

The problem can be solved in several ways using unmanaged code. Global synchronization objects: mutexes, semaphores and events. We will consider the latter.
At first we need to create a permanent identifier for our event (Visual Studio has a built-in GUID generator: Tools->Create GUID):

private static readonly Guid SingleInstanceGuid= new Guid ( «1DADFDD1-DDD1-4390-95B9-5852CFB39807» );

Then we use the unmanageable code :

private const int ERROR_ALREADY_EXISTS = 183; //the error code returned in case of an already existing event
[DllImport( «coredll.dll» , SetLastError = true )]
private static extern IntPtr CreateEvent( IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
[DllImport( «coredll.dll» , SetLastError = true )]
private static extern bool CloseHandle( IntPtr hObject);
[DllImport( «coredll.dll» , SetLastError = true )]
private static extern IntPtr FindWindow( string className, string wndName);

Create an event, get an error code, returnthe answer :

public static bool IsSingleInstance() {
var path = Assembly GetExecutingAssembly().GetName().CodeBase;
handle = CreateEvent( IntPtr Zero, false , false , SingleInstanceGuid.ToString());
var error = Marshal.GetLastWin32Error();
//If the event already exists, find a running application and send the 0x8001 command to it, which should re-activate the application
if (error == ERROR_ALREADY_EXISTS) {
var hWnd = FindWindow( "#NETCF_AGL_PARK_" + path, string Empty);
if (hWnd != IntPtr Zero) {
var msg = Message.Create(hWnd, 0x8001, ( IntPtr )0, ( IntPtr )0);
MessageWindow.SendMessage( ref msg);
}
return false ;
}
return true ;
}

Before closing the application, close the event :

public static void CloseHandle() {
CloseHandle(handle);
}

Put all this code into a class, for example SingleInstance.cs. In practice, it is used as follows in the program.cs file:

if (!SingleInstance.IsSingleInstance()) {
return ;
}
try {
Application.Run( new Form1());
} catch (Exception ex) {
} finally {
SingleInstance.CloseHandle();
} * This source code was highlighted with Source Code Highlighter

A variant using mutexes has a similar idea.
I hope someone will find this solution useful.

You may also like