如何确保我的应用程序的单个实例,并在尝试打开第二个实例时将焦点设置为它?
我试过了:
public partial class Form1 : Form {
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern
IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("USER32.DLL")]
public static extern
Boolean SetForegroundWindow(IntPtr hWnd);
private void Form1_Load(object sender, EventArgs e)
{
bool isRunning = Process.GetProcesses()
.Where(p => p.MainWindowTitle.Contains(Text))
.Count() > 1;
if (isRunning)
{
FocusWindow(Text);
Application.Exit();
}
}
public static void FocusWindow(string title)
{
SetForegroundWindow(FindWindow(null, title));
}
}
这不关注应用程序。我该如何解决这个问题?
答案 0 :(得分:6)
您可能希望使用Mutex
,这样可以避免以稍微不可靠的方式搜索窗口(想象您重命名主窗体或打开其他窗体)。
bool createdNew;
Mutex m = new Mutex(true, "SomeNameHere", out createdNew);
if (!createdNew)
{
// Application already running. Call it and ask to show it's form.
IpcClientChannel clientChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(clientChannel, true);
RemotingConfiguration.RegisterWellKnownClientType(typeof(ExchangeBase), "ipc://SomeNameHere/YourAppBase");
ExchangeBase Exchange = new ExchangeBase();
Exchange.ShowForm();
}
else
{
IpcServerChannel serverChannel = new IpcServerChannel("SomeNameHere");
ChannelServices.RegisterChannel(serverChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ExchangeBase), "YourAppBase", WellKnownObjectMode.SingleCall);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new FormMain();
if (!MainForm.StopLoading)
{
Application.Run(MainForm);
// Keep the mutex reference alive until the termination of the program.
GC.KeepAlive(m);
}
}
答案 1 :(得分:2)
您似乎已将Text
作为参数传递给FocusWindow
方法,但在进行Contains
检查时。我打赌文本只是部分窗口标题,因此导致FindWindow
失败。尝试传递窗口句柄的全文,如:
var proc = Process.GetProcesses()
.Where(p => p.MainWindowTitle.Contains(Text))
.FirstOrDefault();
if (proc != null)
{
FocusWindow(p.MainWindowTitle);
Application.Exit();
}
答案 2 :(得分:1)
它可能是由同一个窗口标题引起的,因此FindWindow获取实际的窗口句柄,尝试使用EnumWindows函数而不是FindWindow。
答案 3 :(得分:1)
对表单加载执行此检查不正确。您应该使用Mutex
来确保只有一个应用程序实例正在运行。有关如何执行此操作以及将焦点设置为现有实例的示例,请参阅this article。
答案 4 :(得分:0)
将此代码放在App.xaml.cs文件中:
using System.Runtime.InteropServices;
#region SetWindowPos Definitions
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOZORDER = 0x0004;
const UInt32 SWP_NOREDRAW = 0x0008;
const UInt32 SWP_NOACTIVATE = 0x0010;
const UInt32 SWP_FRAMECHANGED = 0x0020;
const UInt32 SWP_SHOWWINDOW = 0x0040;
const UInt32 SWP_HIDEWINDOW = 0x0080;
const UInt32 SWP_NOCOPYBITS = 0x0100;
const UInt32 SWP_NOOWNERZORDER = 0x0200;
const UInt32 SWP_NOSENDCHANGING = 0x0400;
#endregion
#region OnStartup
protected override void OnStartup(StartupEventArgs e)
{
// Only allow one instance of the application
Process thisProc = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(thisProc.ProcessName);
if (processes.Length > 1)
{
Application.Current.Shutdown();
SetWindowPos(processes[1].MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(processes[1].MainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE);
}
else
{
base.OnStartup(e);
}
}
#endregion