2012-01-13 23 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 
相關問題