代码之家  ›  专栏  ›  技术社区  ›  tzup

如何获取WinForm应用程序中最顶层窗体的句柄?

  •  8
  • tzup  · 技术社区  · 15 年前

    我有一个WinForm应用程序有其他子窗体(而不是MDI)。如果用户按“Esc”,即使没有焦点,也应关闭最上面的窗体。

    我可以使用键盘挂钩全局捕获转义,但我还需要关闭窗体的句柄。

    我想有一种方法可以使用win32 api做到这一点,但是有没有使用托管代码的解决方案?

    5 回复  |  直到 11 年前
        1
  •  7
  •   tzup    15 年前

    以下是获取使用win32的最顶层表单的一种方法(虽然不是很优雅,但可以工作):

    public const int GW_HWNDNEXT = 2; // The next window is below the specified window
    public const int GW_HWNDPREV = 3; // The previous window is above
    
    [DllImport("user32.dll")]
    static extern IntPtr GetTopWindow(IntPtr hWnd);
    
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool IsWindowVisible(IntPtr hWnd);
    
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
    public static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);
    
    /// <summary>
    /// Searches for the topmost visible form of your app in all the forms opened in the current Windows session.
    /// </summary>
    /// <param name="hWnd_mainFrm">Handle of the main form</param>
    /// <returns>The Form that is currently TopMost, or null</returns>
    public static Form GetTopMostWindow(IntPtr hWnd_mainFrm)
    {
        Form frm = null;
    
        IntPtr hwnd = GetTopWindow((IntPtr)null);
        if (hwnd != IntPtr.Zero)
        {
            while ((!IsWindowVisible(hwnd) || frm == null) && hwnd != hWnd_mainFrm)
            {
                // Get next window under the current handler
                hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
    
                try
                {
                    frm = (Form)Form.FromHandle(hwnd);
                }
                catch
                {
                    // Weird behaviour: In some cases, trying to cast to a Form a handle of an object 
                    // that isn't a form will just return null. In other cases, will throw an exception.
                }
            }
        }
    
        return frm;
    }
    
        2
  •  3
  •   Simon Randy Burden    12 年前

    用这个怎么样 Application.Openforms

    Form GetTopMostForm()
    {
        return Application.OpenForms
            .Cast<Form>()
            .First(x => x.Focused);
    }
    
        3
  •  3
  •   fred    11 年前

    我知道这是一个4年前的线程,但我也遇到了类似的问题,我只是想出了一个替代的解决方案,以防其他人遇到这个问题,不想把win32调用搞得一团糟。

    我认为最上面的表单将是最后激活的表单。因此,您可以保留一个单独的表单集合,类似于application.openforms,但这个集合将按上次激活时的顺序排列。每当激活窗体时,将其移动到集合的第一个项。每当看到Esc键时,都会关闭集合[0]并将其移除。

        4
  •  1
  •   Bogdan_Ch    15 年前

    应用程序对象使用FormCollection通过OpenForms属性列出应用程序中当前打开的表单。

    http://msdn.microsoft.com/en-us/library/system.windows.forms.application.openforms.aspx

    然后可以检查每个窗体的topmost()属性。当你找到一个最上面的形状,你就关闭它。

        5
  •  1
  •   NascarEd    15 年前

    您可以在最顶层的表单中实现一个类似于单例的模式,并提供一个静态属性,该属性返回自身的一个实例并简单地关闭它。

       public class MainForm : Form
       {
          private static MainForm mainForm;
    
          public static MainForm { get { return mainForm; } }
    
          public MainForm()
          {
             mainForm = this;
          }
       }
    
    
       // When the ESC key is pressed...
       MainForm.MainForm.Close();