我有一个应用程序,它一次只能打开一个自己的实例。为了强制执行此操作,我使用以下代码:
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.ProcessName == me.ProcessName)
if (p.Id != me.Id)
{
//if already running, abort this copy.
return;
}
}
//launch the application.
//...
工作正常。我还希望它能够集中已经运行的副本的形式。也就是说,在返回之前,我想把这个应用程序的另一个实例带到前台。
我该怎么做?
Re:SetForeGroundWindow:
SetForeGroundWindow工作到了一点:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
//...
if (p.Id != me.Id)
{
//if already running, focus it, and then abort this copy.
SetForegroundWindow(p.MainWindowHandle);
return;
}
//...
如果未将窗口最小化,则会将窗口置于前台。真棒。 但是,如果窗口IS最小化,它将保持最小化。
需要取消最小化。
通过SwitchToThisWindow解决方案(Works!):
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[STAThread]
static void Main()
{
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName);
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.Id != me.Id)
{
SwitchToThisWindow(p.MainWindowHandle, true);
return;
}
}
//now go ahead and start our application ;-)
答案 0 :(得分:10)
我遇到了同样的问题,SwitchToThisWindow()对我来说效果最好。唯一的限制是您必须安装XP sp1。我玩SetForegroundWindow,ShowWindow,他们都把窗口拉到视野中。
答案 1 :(得分:3)
与OP相同,我发现当窗口最小化时单独SetForegroundWindow
是不够的。由于我不想使用SwitchToThisWindow
,我选择ShowWindow
后跟SetForegroundWindow
。
适合我!
private const SW_SHOWNORMAL = 1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean
End Function
Sub SetForeground()
Dim processes As Process() = Process.GetProcessesByName("myprocess")
For Each p as Process in processes
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL)
SetForegroundWindow(p.MainWindowHandle)
Next
End Sub
答案 2 :(得分:3)
C#相当于Tom Juergens的答案。对我来说就像是一种魅力。
private const int SW_SHOWNORMAL = 1;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetForegroundWindow(IntPtr hwnd);
public void SetForeground()
{
Process[] processes = Process.GetProcessesByName("process name");
foreach (Process p in processes) {
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(p.MainWindowHandle);
}
}
答案 3 :(得分:2)
我相信你会想要SetForegroundWindow
答案 4 :(得分:2)
完整的旁注......
您可以使用
Process.GetProcessesByName(me.ProcessName)
而不是循环遍历系统上运行的所有进程......
<强>更新强>
PInvoke这类事情的规则......
答案 5 :(得分:0)
您是否可以获取Process对象的MainWindowHandle属性并向其发送一条WM_USER消息,您可以将其解释为“其他一些实例希望将我带到前面”。
答案 6 :(得分:0)
这是桌面应用程序中非常常见的行为,在创建新的WPF应用程序时,我经常必须这样做。所以我创建了一个从Application继承的SingletonApp类:
public class SingletonApp : Application
{
private static readonly System.Threading.Mutex mutex;
private static readonly string processName;
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hwnd);
static SingletonApp()
{
processName = Process.GetCurrentProcess().ProcessName;
mutex = new System.Threading.Mutex(false, $"Local\\{processName}");
}
/// <summary>
/// A base class for application needing to prevent multiple instances
/// </summary>
public SingletonApp()
{
if (!mutex.WaitOne(0, false))
{
// Give focus to existing instance before shutdown
BringToFront(processName);
Current.Shutdown();
}
}
public void BringToFront(string processName)
{
Process process = Process.GetProcessesByName(processName).FirstOrDefault();
if (process != null)
{
// In case of window is minimized
ShowWindow(process.MainWindowHandle, 1); // 1 = Normal
SetForegroundWindow(process.MainWindowHandle);
}
}
}
要使用它,只需从SingletonApp继承,而不是从App.xaml.cs中的Application继承:
public partial class App : SingletonApp
也不要忘记更新App.xaml:
<utils:SingletonApp x:Class="MyApp.App"
[...]
xmlns:utils="clr-namespace:MyApp.Utils"
Startup="App_OnStartup">
有了它,在每个新的桌面客户端中实现此行为变得非常容易。