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

发布于 2024-07-25 06:26:33 字数 176 浏览 4 评论 0原文

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

我可以使用键盘钩子全局捕获 Escape,但我还需要关闭表单的句柄。

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

I have a WinForm app that has other child forms (not mdi). If the user presses "Esc" the topmost form should be closed even if it doesn't have the focus.

I can use a keyboard hook to globally catch the Escape but I also need the handle of the form to be closed.

I guess there is a way to do that using Win32 API, but is there a solution using managed code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

雨轻弹 2024-08-01 06:26:33

这是获取使用 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;
}

Here is one way to get the topmost form that uses Win32 (not very elegant, but it works):

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;
}
江挽川 2024-08-01 06:26:33

使用 Application.Openforms 怎么样?

Form GetTopMostForm()
{
    return Application.OpenForms
        .Cast<Form>()
        .First(x => x.Focused);
}

How about this using Application.Openforms

Form GetTopMostForm()
{
    return Application.OpenForms
        .Cast<Form>()
        .First(x => x.Focused);
}
二手情话 2024-08-01 06:26:33

我知道这是一个 4 年前的帖子,但我遇到了类似的问题,只是想出了一个替代解决方案,以防万一其他人偶然发现这个问题并且不想乱搞 Win32 调用。

我认为最顶层的表单将是最后激活的表单。 因此,您可以保留一个单独的表单集合,类似于 Application.OpenForms,但该集合将按每个表单上次激活的时间排序。 每当激活表单时,将其移至集合的第一项。 每当你看到 ESC 键时,你就会关闭 collection[0] 并将其删除。

I know this is a 4 yr old thread, but I had a similar problem and just came up with an alternative solution just in case anyone else stumbles on this question and doesn't want to mess around with Win32 calls.

I assume the top-most form will be the one that was last activated. So you could keep a separate collection of forms, similar to Application.OpenForms, except this collection would be ordered by when each was last activated. Whenever a form is activated, move it to the first item of the collection. Whenever you see the ESC key, you would close collection[0] and remove it.

彼岸花似海 2024-08-01 06:26:33

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

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

然后你可以检查 TopMost() 属性每种形式。 当您找到最顶层的表单时,将其关闭。

FormCollection is used by the Application object to list the currently open forms in an application through the OpenForms property

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

Then you could check TopMost() property of each form. And when you find a topmost form, you close it.

时光倒影 2024-08-01 06:26:33

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

   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();

You could implement a singleton-like pattern in your topmost form, and provide a static property that returns the one instance of itself and simply close it.

   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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文