I often write .net applications that only support one instance. Formerly I used .net-remoting and now WCF to detect if already an instance of my app is running and giving the focus to this instance.
My question is, if there is with .net4 a better solution available to achieve single instance applications (or is there in general a better solution available, because loading the WCF or remoting assembly at the very start of the application has a bad performance influence)
Update
Thanks for all the post. The answer to my initial question seems to be “no, there is nothing new to achieve single instance applications within .net 4”.
Thanks to all the additional information, I will change my current projects to use a Mutex to provide the desired functionality. I accepted the answer of Bob Moore because it has the most information attached to it, but thanks to all who posted useful information.
The traditional way to do this is with a mutex, e.g.
bool bNew = true;
using (Mutex mutex = new Mutex(true, "MYAPP_0D36E4C9-399D-4b05-BDA3-EE059FB77E8D", out bNew))
{
if (bNew)
{
// blah, blah,
Application.Run(new MainForm());
}
}
Edit:
I found this code to invoke SetForegroundWindow online, so you can find the other instance of your app and bring it forward:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
Process me = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName (me.ProcessName))
{
if (process.Id != me.Id)
{
SetForegroundWindow (process.MainWindowHandle);
break;
}
}
Note that in modern Windows implementations you can only give the foreground away.
I use a Mutex, and FindWindow to do this.
Concerning your comment on another answer:
For information on Local and Global mutexes in Terminal Services, follow this link.
Terminal Services client processes can use object names with a "Global\" or "Local\" prefix to explicitly create an object in the global or session name space.
This is the code I use to activate the window:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SH_SHOW = 5;
private const int SH_RESTORE = 9;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
public void Activate(IntPtr hwnd)
{
if (IsIconic(hwnd))
ShowWindow(hwnd, SH_RESTORE);
else
ShowWindow(hwnd, SH_SHOW);
SetForegroundWindow(hwnd);
}
There's a simpler way - with help of WindowsFormsApplicationBase class from Microsoft.VisualBasic.ApplicationServices:
using System;
using System.Collections.Generic;
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
IsSingleInstance = true;
}
private MyApp m_app;
protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
// here we create our WPF application
m_app = new MyApp();
m_app.Run();
return false;
}
protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
m_app.DispatchCommandLineParams(e.CommandLine);
}
}
public class MyApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
DispatchCommandLineParams(e.Args);
}
public void DispatchCommandLineParams(IEnumerable<string> cmdParams)
{
// process command line parameters
Console.WriteLine(this.GetHashCode() + " - dispatched");
}
}
public class Program
{
[STAThread]
public static void Main(string[] args)
{
var wrapper = new SingleInstanceApplicationWrapper();
wrapper.Run(args);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With