确保程序只有一个实例在运行
2008-09-10 23:11
627 查看
In some scenarios, you may wish to ensure that a user can run only one instance of your application at a time. Besides ensuring that only a single instance of your application is running, you may also want to bring the instance already running to the front and restore it, if it is minimized.
First, to ensure that only one instance of your application is running at a time, the best method I've found is to create a mutex that is held by the operating system (thanks to Michael Covington). This will put a request to the operating system that a mutex be created if one does not already exist. Only one mutex can ever be created at a time, so if you request a new one and it cannot be created, you can safely assume that your application is already running.
using System.Threading
using System.Runtime.InteropServices;
public class Form1 : Form
{
[STAThread]
static void Main()
{
bool createdNew;
Mutex m = new Mutex(true, "YourAppName", out createdNew);
if (! createdNew)
{
// app is already running...
MessageBox.Show("Only one instance of this application is allowed at a time.");
return;
}
Application.Run(new Form1());
// keep the mutex reference alive until the normal termination of the program
GC.KeepAlive(m);
}
}
The above code will work for the vast majority of your needs. It will also run under scenarios where your code is executing with less than FullTrust permissions (see Code Access Security in MSDN for further information).
If your application can run with Full Trust permissions, we can take this a step further and find the window of the application instnace already running and bring it to the front for the user:
public class Form1 : Form
{
[STAThread]
static void Main()
{
bool createdNew;
System.Threading.Mutex m = new System.Threading.Mutex(true, "YourAppName", out createdNew);
if (! createdNew)
{
// see if we can find the other app and Bring it to front
IntPtr hWnd = FindWindow("WindowsForms10.Window.8.app3", "YourAppName");
if(hWnd != IntPtr.Zero)
{
Form1.WINDOWPLACEMENT placement = new Form1.WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hWnd, ref placement);
if(placement.showCmd != SW_NORMAL)
{
placement.showCmd = SW_RESTORE;
SetWindowPlacement(hWnd, ref placement);
SetForegroundWindow(hWnd);
}
}
return;
}
Application.Run(new Form1());
// keep the mutex reference alive until the normal termination of the program
GC.KeepAlive(m);
}
private const int SW_NORMAL = 1; // see WinUser.h for definitions
private const int SW_RESTORE = 9;
[DllImport("User32",EntryPoint="FindWindow")]
static extern IntPtr FindWindow(string className, string windowName);
[DllImport("User32",EntryPoint="SendMessage")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32",EntryPoint="SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32",EntryPoint="SetWindowPlacement")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("User32",EntryPoint="GetWindowPlacement")]
private static extern bool GetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
private struct POINTAPI
{
public int x;
public int y;
}
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINTAPI ptMinPosition;
public POINTAPI ptMaxPosition;
public RECT rcNormalPosition;
}
}
As you can see, with minimal effort, you can easily add a polished touch to your application. This might even help you avoid some extra legwork in ensuring that there are no issues with running multiple instances of your app at the same time that you might have to address.
For more information about the Platform Invoke mechanisms to call Win32 API functions, I recommend that you check out .NET Framework Solutions: In Search of the Lost Win32 API by John Mueller and Charles Petzold's seminal classic Programming Windows.
Until Longhorn comes out and more of the Windows platform becomes managed, platform invokes and interop will remain a key technology to understand and use to your advantage to fill the gaps left by the Windows Forms framework.
UPDATE:
Visual Studio .NET 2005 (aka. “Whidbey”) will let you specify Single Instance behavior for Visual Basic .NET projects through the Project Properties page. Curious as to why this option is available for VB projects and not for C# projects, as this seems to instruct the runtime or some framework library not to load more than one instance.
Anther way:
int iLength = System.Diagnostics.Process.GetProcessesByName(System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length;
if (iLength > 1)
{
return;
}
First, to ensure that only one instance of your application is running at a time, the best method I've found is to create a mutex that is held by the operating system (thanks to Michael Covington). This will put a request to the operating system that a mutex be created if one does not already exist. Only one mutex can ever be created at a time, so if you request a new one and it cannot be created, you can safely assume that your application is already running.
using System.Threading
using System.Runtime.InteropServices;
public class Form1 : Form
{
[STAThread]
static void Main()
{
bool createdNew;
Mutex m = new Mutex(true, "YourAppName", out createdNew);
if (! createdNew)
{
// app is already running...
MessageBox.Show("Only one instance of this application is allowed at a time.");
return;
}
Application.Run(new Form1());
// keep the mutex reference alive until the normal termination of the program
GC.KeepAlive(m);
}
}
The above code will work for the vast majority of your needs. It will also run under scenarios where your code is executing with less than FullTrust permissions (see Code Access Security in MSDN for further information).
If your application can run with Full Trust permissions, we can take this a step further and find the window of the application instnace already running and bring it to the front for the user:
public class Form1 : Form
{
[STAThread]
static void Main()
{
bool createdNew;
System.Threading.Mutex m = new System.Threading.Mutex(true, "YourAppName", out createdNew);
if (! createdNew)
{
// see if we can find the other app and Bring it to front
IntPtr hWnd = FindWindow("WindowsForms10.Window.8.app3", "YourAppName");
if(hWnd != IntPtr.Zero)
{
Form1.WINDOWPLACEMENT placement = new Form1.WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hWnd, ref placement);
if(placement.showCmd != SW_NORMAL)
{
placement.showCmd = SW_RESTORE;
SetWindowPlacement(hWnd, ref placement);
SetForegroundWindow(hWnd);
}
}
return;
}
Application.Run(new Form1());
// keep the mutex reference alive until the normal termination of the program
GC.KeepAlive(m);
}
private const int SW_NORMAL = 1; // see WinUser.h for definitions
private const int SW_RESTORE = 9;
[DllImport("User32",EntryPoint="FindWindow")]
static extern IntPtr FindWindow(string className, string windowName);
[DllImport("User32",EntryPoint="SendMessage")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32",EntryPoint="SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32",EntryPoint="SetWindowPlacement")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("User32",EntryPoint="GetWindowPlacement")]
private static extern bool GetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
private struct POINTAPI
{
public int x;
public int y;
}
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINTAPI ptMinPosition;
public POINTAPI ptMaxPosition;
public RECT rcNormalPosition;
}
}
As you can see, with minimal effort, you can easily add a polished touch to your application. This might even help you avoid some extra legwork in ensuring that there are no issues with running multiple instances of your app at the same time that you might have to address.
For more information about the Platform Invoke mechanisms to call Win32 API functions, I recommend that you check out .NET Framework Solutions: In Search of the Lost Win32 API by John Mueller and Charles Petzold's seminal classic Programming Windows.
Until Longhorn comes out and more of the Windows platform becomes managed, platform invokes and interop will remain a key technology to understand and use to your advantage to fill the gaps left by the Windows Forms framework.
UPDATE:
Visual Studio .NET 2005 (aka. “Whidbey”) will let you specify Single Instance behavior for Visual Basic .NET projects through the Project Properties page. Curious as to why this option is available for VB projects and not for C# projects, as this seems to instruct the runtime or some framework library not to load more than one instance.
Anther way:
int iLength = System.Diagnostics.Process.GetProcessesByName(System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length;
if (iLength > 1)
{
return;
}
相关文章推荐
- Win32 程序 确保只有一个实例运行
- C# 确保程序只有一个实例在运行[转]
- 确保只有一个程序实例运行(C#)之解决方案
- 确保只有一个程序实例运行(C#)之解决方案
- 保证Winform程序只有一个实例在运行
- 保证程序只有一个实例运行 &&& 动态调用DLL的研究
- 如何让一个程序只有一个运行实例
- 让你的Java程序只有一个进程实例在运行
- 确保一个程序只存在一个实例运行
- 保证程序只有一个运行实例
- 如何确保只有一个应用程序实例在运行?
- WPF程序只有一个实例运行
- 让程序只有一个实例运行
- 使用互斥量保证程序最多只有一个实例运行
- 确保程序只运行一个实例
- linux入手小程序——任何一个程序的运行只有借助于操作系统才能得以顺利完成的小实例
- 利用互斥控制程序只有一个运行实例
- 让程序只有一个应用程序实例在运行
- 保证程序只有一个实例运行并且先将旧实例关闭再运行新实例
- 让程序只有一个进程实例在运行