2010-07-09 105 views
8

我經常編寫只支持一個實例的.net應用程序。以前我使用.net遠程和現在WCF來檢測,如果我的應用程序的實例已經運行,並將焦點放在這個實例。我的問題是,如果.net4有一個更好的解決方案可用於實現單實例應用程序(或通常有更好的解決方案可用,因爲在應用程序的開始加載WCF或遠程處理程序集有一個性能不良的影響).NET 4單一應用程序實例

更新

感謝所有的職位。對我最初的問題的答案似乎是「不,在.net 4內部實現單實例應用程序並沒有什麼新東西。

感謝所有的額外信息,我會改變我目前的項目使用互斥來提供所需的功能。我接受了鮑勃摩爾的答案,因爲它擁有最多的信息,但是要感謝所有發佈有用信息的人。

+1

沒有什麼特別的 看看這個(例如對於VB.net!)。淨4.WCF和遠程處理聽起來像這樣簡單的任務的巨大開銷 – Andrey 2010-07-09 09:58:01

+0

可能重複[什麼是正確的方式來創建一個單一的實例應用程序?](http:// stackoverflow。COM /問題/ 19147 /什麼,是最正確的路,來創建-A-單實例的應用程序) – ChrisF 2010-07-09 10:12:22

+0

@Andrey:確實是這樣,它的開銷,但我不得不說,在大多數論文我的應用程式無論如何使用WCF/Remoting,這證明了它們的使用。但是程序集加載的時間點不好,因爲它延長了應用程序加載/初始化的時間。 – HCL 2010-07-09 10:20:28

回答

11

傳統的做法是使用互斥鎖,

bool bNew = true; 
using (Mutex mutex = new Mutex(true, "MYAPP_0D36E4C9-399D-4b05-BDA3-EE059FB77E8D", out bNew)) 
{ 
    if (bNew) 
    { 
     // blah, blah, 
     Application.Run(new MainForm()); 
    } 
} 

編輯:

我發現這個代碼在網上調用SetForegroundWindow,所以你可以找到你的應用程序的其他實例,並顯示它:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetForegroundWindow(IntPtr hWnd); 


Process me = Process.GetCurrentProcess(); 
foreach (Process process in Process.GetProcessesByName (me.ProcessName)) 
{ 
    if (process.Id != me.Id) 
    { 
     SetForegroundWindow (process.MainWindowHandle); 
     break; 
    } 
} 

注意,在現代Windows實現你只能放棄前景。

+0

這是否也適用於終端 - 服務器環境? – HCL 2010-07-09 09:58:42

+1

互斥鎖可以是每個會話或機器寬。 – GvS 2010-07-09 10:00:20

+0

以及如何激活現有的應用程序(焦點)? PInvoke的? – HCL 2010-07-09 10:03:15

2

我使用MutexFindWindow來做到這一點。

關於對另一個答案您的評論:
有關在終端服務,follow this link局部和全局的互斥信息。

終端服務客戶端處理 可以使用對象名稱與「全球\」 或「本地\」前綴明確 創建全球或 會話名稱空間中的對象。

這是我使用激活窗口中的代碼:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool IsIconic(IntPtr hWnd); 

[DllImport("user32.dll")] 
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 
private const int SH_SHOW = 5; 
private const int SH_RESTORE = 9; 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetForegroundWindow(IntPtr hWnd); 

public void Activate(IntPtr hwnd) 
{ 
    if (IsIconic(hwnd)) 
     ShowWindow(hwnd, SH_RESTORE); 
    else 
     ShowWindow(hwnd, SH_SHOW); 

    SetForegroundWindow(hwnd); 
} 
2

有一個簡單的方法:

using System; 
using System.Collections.Generic; 

public class SingleInstanceApplicationWrapper : 
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase 
{ 
    public SingleInstanceApplicationWrapper() 
    { 
    IsSingleInstance = true; 
    } 

    private MyApp m_app; 
    protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e) 
    { 
    // here we create our WPF application 
    m_app = new MyApp(); 
    m_app.Run(); 
    return false; 
    } 

    protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e) 
    { 
    m_app.DispatchCommandLineParams(e.CommandLine); 
    } 
} 

public class MyApp : System.Windows.Application 
{ 
    protected override void OnStartup(System.Windows.StartupEventArgs e) 
    { 
    base.OnStartup(e); 
    DispatchCommandLineParams(e.Args); 
    } 
    public void DispatchCommandLineParams(IEnumerable<string> cmdParams) 
    { 
    // process command line parameters 
    Console.WriteLine(this.GetHashCode() + " - dispatched"); 
    } 
} 
public class Program 
{ 
    [STAThread] 
    public static void Main(string[] args) 
    { 
    var wrapper = new SingleInstanceApplicationWrapper(); 
    wrapper.Run(args); 
    } 
} 
相關問題