代码之家  ›  专栏  ›  技术社区  ›  Zach Johnson

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

  •  9
  • Zach Johnson  · 技术社区  · 15 年前

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

    PresentationSource.FromVisual 而窗口尚未创建,则返回 PresentationSource 窗内插板 Handle 财产是 IntPtr.Zero

    我试过打电话 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);
    
    4 回复  |  直到 15 年前
        1
  •  3
  •   Chris Taylor    15 年前

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

      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;
    
        2
  •  22
  •   Nazar Grynko    8 年前

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

        3
  •  3
  •   J Pollack    14 年前

    如果WindowInteropHelper的句柄为NULL,我正在寻找一个解决方案。希望这篇文章能提供一些额外的信息来解决这个问题。

    一种解决方案是使用:

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

    这仅适用于.NET Framework 4。

    目前我正在使用.NETFramework3.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;
            }
        }
    }
    

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

        4
  •  1
  •   Community Mohan Dere    9 年前

    我被困在同一个问题上 J Pollack's answer (因为在我看来它更干净),但是需要一些既能在.NET运行时2.0上运行又能在.NET运行时4.0上运行的东西。

    但当我这么做的时候,我却得到了一个丑陋的结局 MissingMethodException 安全创建窗口 在.NET runtime 4.0中不再存在。为了使代码在两个运行时都能工作,我决定捕获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;
        }