2010-07-13 103 views
1

我有以下情況: WinForms應用程序只允許運行此應用程序的一個實例(此處使用互斥鎖來檢查)。從一些paramatere開始的應用程序是runnig,但隱藏。當有人再次點擊應用程序時,Mutex會檢測到該應用程序已在運行,並通過本地方法調用「取消隱藏」主窗體(請參見下面的方法BringWindowToFront)。使用PInvoke顯示錶格

這裏是找到並顯示窗體窗口代碼:

public static class NativeMethods 
{ 
    public enum ShowWindowOptions 
    { 
     FORCEMINIMIZE = 11, 
     HIDE = 0, 
     MAXIMIZE = 3, 
     MINIMIZE = 6, 
     RESTORE = 9, 
     SHOW = 5, 
     SHOWDEFAULT = 10, 
     SHOWMAXIMIZED = 3, 
     SHOWMINIMIZED = 2, 
     SHOWMINNOACTIVE = 7, 
     SHOWNA = 8, 
     SHOWNOACTIVATE = 4, 
     SHOWNORMAL = 1 
    } 

    [DllImport("user32.dll")] 
    public static extern int ShowWindow(int hwnd, int cmdShow); 

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)] 
    public static extern IntPtr FindWindow(String lpClassName, String lpWindowName); 

    [DllImport("USER32.DLL")] 
    public static extern bool SetForegroundWindow(IntPtr hWnd); 

    public static void BringWindowToFront(string windowTitle) 
    { 
     // Get a handle to the application. 
     IntPtr handle = FindWindow(null, windowTitle); 

     // Verify that app is a running process. 
     if (handle == IntPtr.Zero) 
     { 
      return; 
     } 

     // With this line you have changed window status from example, minimized to normal 
     ShowWindow((int)handle, (int)ShowWindowOptions.SHOWDEFAULT); 

     // Make app the foreground application 
     SetForegroundWindow(handle); 
    } 
} 

一切都很好,但我需要一個功能呢。 我想在主窗體第一次取消隱藏時再顯示另一個窗體。通常我會通過表格_Shown事件。但是當我使用PInvoke方法來顯示窗口時,這個事件不會被激活。

所以基本上我想顯示其他形式時,將顯示主窗體(使用的ShowWindow PInvoke的方法)

這可能嗎?任何其他想法如何實現它?

預先感謝您。

+0

你是否堅持P/Invoke mec hanism爲了做到這一點?還有其他方法可以完全在C#代碼中生成單個實例應用程序。 – ChrisF 2010-07-13 20:18:25

+0

我通過Mutex實現了單例。現在我堅持要顯示額外的窗體後,我顯示主窗口由公共靜態extern int ShowWindow(int hwnd,int cmdShow); – binball 2010-07-13 20:53:07

回答

2

編寫單實例應用程序很麻煩,你不需要,.NET框架已經很好地支持它們了,Project + Add Reference,選擇Microsoft.VisualBasic。 Program.cs文件,並使其看起來像這樣:

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 
using Microsoft.VisualBasic.ApplicationServices; 

namespace WindowsFormsApplication1 { 
    class Program : WindowsFormsApplicationBase { 
     [STAThread] 
     static void Main(string[] args) { 
      var prg = new Program(); 
      prg.EnableVisualStyles = true; 
      prg.IsSingleInstance = true; 
      prg.MainForm = new Form1(); 
      prg.Run(args); 
     } 

     protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e) { 
      var main = this.MainForm as Form1; 
      main.WindowState = FormWindowState.Normal; 
      main.BringToFront(); 
      // You could do something interesting with the command line arguments: 
      //foreach (var arg in e.CommandLine) { 
      // main.OpenFile(arg); 
      //} 
     } 
    } 
} 
+0

Scott Hanselman對此有一個很好的發帖 - http://www.hanselman.com/blog/CommentView.aspx?guid=d2f676ea-025b-4fd6-ae79-80b04a34f24c – ChrisF 2010-07-14 09:19:48

+0

Hans,謝謝你的這個例子。在我的特殊情況下,這種單實例應用程序的方法比Mutex好得多。 所以我只是添加frmAnother frm = new frmAnother();在main.BringToFront()之後;它完全符合我的需求。 Thx! – binball 2010-07-14 09:43:56

2

Form.Shown事件僅在第一次顯示錶單(即加載後)時觸發,稍後執行任何其他操作(例如隱藏然後重新顯示)都不會觸發事件。欲瞭解更多信息,請參閱:http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx

有一對夫婦,可能你的情況是有用的其他事件:

如果這些都不起作用,並且您必須使用P/Invoke,那麼我將使用SetActiveWindow,它將發送一條WM_ACTIVATE消息,該消息應強制執行Form.Activated

請注意,如果這不起作用(因爲SetActiveWindow發送一個WM_ACTIVATE低位爲1,表明窗口沒有被鼠標激活,那麼你可以通過直接發送消息來解決這個問題這個窗口帶有你自己的WM_ACTIVATE消息

+0

thx這個解釋 – binball 2010-07-14 09:45:52