强制创建 WPF 窗口的本机 Win32 句柄

发布于 2024-09-09 02:44:45 字数 1578 浏览 6 评论 0原文

我需要访问一些 WPF 窗口的 Win32 窗口句柄,以便可以处理 Win32 激活消息。我知道我可以使用 PresentationSource.FromVisualWindowInteropHelper 来获取 Win32 窗口句柄,但如果尚未创建 WPF 窗口,我就会遇到问题。

如果我使用 PresentationSource.FromVisual 并且尚未创建窗口,则返回的 PresentationSource 为 null。如果我使用 WindowInteropHelper 并且尚未创建窗口,则 Handle 属性为 IntPtr.Zero (null)。

在尝试访问句柄之前,我尝试在窗口上调用 this.Show()this.Hide() 。然后我可以获得句柄,但窗口会在屏幕上短暂闪烁(丑陋!)。

有谁知道强制创建 WPF 窗口的方法吗?在 Windows 窗体中,这就像访问 Form.Handle 属性一样简单。

编辑:我最终选择了克里斯·泰勒答案的变体。在这里,以防对其他人有帮助:

static void InitializeWindow(Window window)
{
    // Get the current values of the properties we are going to change
    double oldWidth = window.Width;
    double oldHeight = window.Height;
    WindowStyle oldWindowStyle = window.WindowStyle;
    bool oldShowInTaskbar = window.ShowInTaskbar;
    bool oldShowActivated = window.ShowActivated;

    // Change the properties to make the window invisible
    window.Width = 0;
    window.Height = 0;
    window.WindowStyle = WindowStyle.None;
    window.ShowInTaskbar = false;
    window.ShowActivated = false;

    // Make WPF create the window's handle
    window.Show();
    window.Hide();

    // Restore the old values
    window.Width = oldWidth;
    window.Height = oldHeight;
    window.WindowStyle = oldWindowStyle;
    window.ShowInTaskbar = oldShowInTaskbar;
    window.ShowActivated = oldShowActivated;
}

// Use it like this:
InitializeWindow(myWpfWindow);

I need to access the Win32 window handles of some of my WPF windows so I can handle Win32 activation messages. I know I can use PresentationSource.FromVisual or WindowInteropHelper to get the Win32 window handle, but I am running into problems if the WPF window has not been created yet.

If I use PresentationSource.FromVisual and the window has not been created, the returned PresentationSource is null. If I use WindowInteropHelper and the window has not been created, the Handle property is IntPtr.Zero (null).

I tried calling this.Show() and this.Hide() on the window before I tried to access the handle. I can then get the handle, but the window flashes momentarily on the screen (ugly!).

Does anyone know of a way to force a WPF window to be created? In Windows Forms this was as easy as accessing the Form.Handle property.

Edit: I ended up going with a variant on Chris Taylor's answer. Here it is, in case it helps someone else:

static void InitializeWindow(Window window)
{
    // Get the current values of the properties we are going to change
    double oldWidth = window.Width;
    double oldHeight = window.Height;
    WindowStyle oldWindowStyle = window.WindowStyle;
    bool oldShowInTaskbar = window.ShowInTaskbar;
    bool oldShowActivated = window.ShowActivated;

    // Change the properties to make the window invisible
    window.Width = 0;
    window.Height = 0;
    window.WindowStyle = WindowStyle.None;
    window.ShowInTaskbar = false;
    window.ShowActivated = false;

    // Make WPF create the window's handle
    window.Show();
    window.Hide();

    // Restore the old values
    window.Width = oldWidth;
    window.Height = oldHeight;
    window.WindowStyle = oldWindowStyle;
    window.ShowInTaskbar = oldShowInTaskbar;
    window.ShowActivated = oldShowActivated;
}

// Use it like this:
InitializeWindow(myWpfWindow);

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

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

发布评论

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

评论(4

茶底世界 2024-09-16 02:44:45

使用 WindowInteropHelper.EnsureHandle,它正是您所需要的。

Use WindowInteropHelper.EnsureHandle, it does exactly what you need.

仙气飘飘 2024-09-16 02:44:45

一种选择是将窗口状态设置为最小化,并且在显示窗口之前不显示在任务栏中。尝试这样的事情。

  IntPtr hWnd;
  WindowInteropHelper helper = new WindowInteropHelper(wnd);

  WindowState prevState = wnd.WindowState;
  bool prevShowInTaskBar = wnd.ShowInTaskbar;

  wnd.ShowInTaskbar = false;
  wnd.WindowState = WindowState.Minimized;
  wnd.Show();
  hWnd = helper.Handle;
  wnd.Hide();

  wnd.ShowInTaskbar = prevShowInTaskBar;
  wnd.WindowState = prevState;

One option is to set window state to minimized and not to show in the taskbar before Showing the window. Try something like this.

  IntPtr hWnd;
  WindowInteropHelper helper = new WindowInteropHelper(wnd);

  WindowState prevState = wnd.WindowState;
  bool prevShowInTaskBar = wnd.ShowInTaskbar;

  wnd.ShowInTaskbar = false;
  wnd.WindowState = WindowState.Minimized;
  wnd.Show();
  hWnd = helper.Handle;
  wnd.Hide();

  wnd.ShowInTaskbar = prevShowInTaskBar;
  wnd.WindowState = prevState;
孤君无依 2024-09-16 02:44:45

如果 WindowInteropHelper 的句柄为 NULL,我正在寻找解决方案。希望这篇文章提供了一些如何解决该问题的附加信息。

一种解决方案是使用:

var window = new Window();
var handle = new WindowInteropHelper(window).EnsureHandle()

这仅适用于 .NET Framework 4。

目前我正在使用 .NET Framework 3.5,因此我需要另一种解决方案。然后我发现一个带有 WindowInteropHelper 扩展方法的论坛线程:

#region

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Interop;

#endregion

namespace System.Windows.Interop
{
    /// <summary>
    ///   Provides NetFX 4.0 EnsureHandle method for
    ///   NetFX 3.5 WindowInteropHelper class.
    /// </summary>
    public static class WindowInteropHelperExtension
    {
        /// <summary>
        ///   Creates the HWND of the window if the HWND has not been created yet.
        /// </summary>
        /// <param name = "helper">An instance of WindowInteropHelper class.</param>
        /// <returns>An IntPtr that represents the HWND.</returns>
        /// <remarks>
        ///   Use the EnsureHandle method when you want to separate
        ///   window handle (HWND) creation from the
        ///   actual showing of the managed Window.
        /// </remarks>
        public static IntPtr EnsureHandle(this WindowInteropHelper helper)
        {
            if (helper == null)
                throw new ArgumentNullException("helper");

            if (helper.Handle == IntPtr.Zero)
            {
                var window = (Window) typeof (WindowInteropHelper).InvokeMember(
                    "_window",
                    BindingFlags.GetField |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, helper, null);

                typeof (Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }

            return helper.Handle;
        }
    }
}

WindowInteropHelper.EnsureHandle() 不期望已经创建窗口。

参考:Alexander Yudakov - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

I was looking for a solution if the WindowInteropHelper's handle is NULL. Hopefully this post gives some additional information how to solve it.

One solution is to use:

var window = new Window();
var handle = new WindowInteropHelper(window).EnsureHandle()

This works only with .NET Framework 4.

At the moment I am using .NET Framework 3.5 so I needed another solution. Then I found a forum thread with a WindowInteropHelper extension method:

#region

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Interop;

#endregion

namespace System.Windows.Interop
{
    /// <summary>
    ///   Provides NetFX 4.0 EnsureHandle method for
    ///   NetFX 3.5 WindowInteropHelper class.
    /// </summary>
    public static class WindowInteropHelperExtension
    {
        /// <summary>
        ///   Creates the HWND of the window if the HWND has not been created yet.
        /// </summary>
        /// <param name = "helper">An instance of WindowInteropHelper class.</param>
        /// <returns>An IntPtr that represents the HWND.</returns>
        /// <remarks>
        ///   Use the EnsureHandle method when you want to separate
        ///   window handle (HWND) creation from the
        ///   actual showing of the managed Window.
        /// </remarks>
        public static IntPtr EnsureHandle(this WindowInteropHelper helper)
        {
            if (helper == null)
                throw new ArgumentNullException("helper");

            if (helper.Handle == IntPtr.Zero)
            {
                var window = (Window) typeof (WindowInteropHelper).InvokeMember(
                    "_window",
                    BindingFlags.GetField |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, helper, null);

                typeof (Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }

            return helper.Handle;
        }
    }
}

The WindowInteropHelper.EnsureHandle() does not expect a window is already created.

Reference: Alexander Yudakov - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

终止放荡 2024-09-16 02:44:45

我陷入了同样的问题,并选择了 J Pollack 的答案(因为它对我来说似乎更干净),但需要一些东西可以在 .NET 运行时 2.0 和 4.0 上运行。

但是当我这样做时,我最终得到了一个丑陋的 MissingMethodException,因为 .NET 运行时 4.0 中不再存在 SafeCreateWindow。为了使代码在两个运行时上都能工作,我决定捕获 MissingMethodException 并调用 .NET 4.0 运行时中的等效项,如下所示:

    public static IntPtr EnsureHandle(this WindowInteropHelper helper)
    {
        if (helper == null)
            throw new ArgumentNullException("helper");

        if (helper.Handle == IntPtr.Zero)
        {
            var window = (Window)typeof(WindowInteropHelper).InvokeMember(
                "_window",
                BindingFlags.GetField |
                BindingFlags.Instance |
                BindingFlags.NonPublic,
                null, helper, null);

            try
            {
                // SafeCreateWindow only exists in the .NET 2.0 runtime. If we try to
                // invoke this method on the .NET 4.0 runtime it will result in a
                // MissingMethodException, see below.
                typeof(Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }
            catch (MissingMethodException)
            {
                // If we ended up here it means we are running on the .NET 4.0 runtime,
                // where the method we need to call for the handle was renamed/replaced
                // with CreateSourceWindow.
                typeof(Window).InvokeMember(
                    "CreateSourceWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, new object[] { false });
            }
        }

        return helper.Handle;
    }

这使我可以使用 .NET 3.5 编译代码,但可以在以下系统上的 .NET 运行时 4.0 上运行它:仅安装了较高的运行时版本(即 Windows 8 及更高版本)。

I was stuck on this same issue and went with J Pollack's answer (because it seems cleaner to me), but needed something that would run both on the .NET runtime 2.0 and 4.0.

But when I did that I ended up with an ugly MissingMethodException because SafeCreateWindow does not exist in the .NET runtime 4.0 anymore. To make the code work on both runtimes I decided to catch the MissingMethodException and invoke the equivalent in the .NET 4.0 runtime instead like this:

    public static IntPtr EnsureHandle(this WindowInteropHelper helper)
    {
        if (helper == null)
            throw new ArgumentNullException("helper");

        if (helper.Handle == IntPtr.Zero)
        {
            var window = (Window)typeof(WindowInteropHelper).InvokeMember(
                "_window",
                BindingFlags.GetField |
                BindingFlags.Instance |
                BindingFlags.NonPublic,
                null, helper, null);

            try
            {
                // SafeCreateWindow only exists in the .NET 2.0 runtime. If we try to
                // invoke this method on the .NET 4.0 runtime it will result in a
                // MissingMethodException, see below.
                typeof(Window).InvokeMember(
                    "SafeCreateWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, null);
            }
            catch (MissingMethodException)
            {
                // If we ended up here it means we are running on the .NET 4.0 runtime,
                // where the method we need to call for the handle was renamed/replaced
                // with CreateSourceWindow.
                typeof(Window).InvokeMember(
                    "CreateSourceWindow",
                    BindingFlags.InvokeMethod |
                    BindingFlags.Instance |
                    BindingFlags.NonPublic,
                    null, window, new object[] { false });
            }
        }

        return helper.Handle;
    }

This allowed me to compile the code with .NET 3.5 but run it on .NET runtime 4.0 on systems that only have the higher runtime version installed (namely Windows 8 and above).

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