2012-01-13 58 views
4

如何确保我的应用程序的单个实例,并在尝试打开第二个实例时将焦点设置为该应用程序?如何强制执行我的应用程序的单个实例?

我想:

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

你肯定FindWindow函数返回一个有效的HWND? – Tigran 2012-01-13 20:00:05

+0

在启动表单之前检查Program.cs是否更有意义?用'count> 0'检查进程名称的实例。 – 2012-01-13 20:03:40

+1

请参阅[C#中的单实例应用程序](http://blogs.msdn.com/b/tyler_whitney/archive/2005/11/28/497604.aspx) – LarsTech 2012-01-13 20:04:48

回答

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); 
    } 
} 
2

它看起来像你传递Text作为参数传递给FocusWindow的方法,但同时做一个Contains检查。我敢打赌,文本只是部分窗口标题,因此,导致FindWindow失败。尝试通过窗口句柄的全文,而不是像:

var proc = Process.GetProcesses() 
        .Where(p => p.MainWindowTitle.Contains(Text)) 
        .FirstOrDefault(); 

     if (proc != null) 
     { 
      FocusWindow(p.MainWindowTitle); 
      Application.Exit(); 
     } 
1

它可能是由相同的Windows标题引起的,所以FindWindow函数得到实际的窗口句柄,尝试使用EnumWindows函数而不是FindWindow函数。

1

对表单加载执行此检查不正确。您应该使用Mutex以确保只有一个应用程序实例正在运行。有关如何执行此操作的示例,请参阅this article,并将焦点设置为现有实例。

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 
相关问题