簡體   English   中英

強制創建WPF Window的本機Win32句柄

[英]Forcing the creation of a WPF Window's native Win32 handle

我需要訪問我的一些WPF窗口的Win32窗口句柄,以便我可以處理Win32激活消息。 我知道我可以使用PresentationSource.FromVisualWindowInteropHelper來獲取Win32窗口句柄,但是如果尚未創建WPF窗口,我遇到了問題。

如果我使用PresentationSource.FromVisual並且尚未創建窗口,則返回的PresentationSource為null。 如果我使用WindowInteropHelper並且尚未創建窗口,則Handle屬性為IntPtr.Zero (null)。

在嘗試訪問句柄之前,我嘗試在窗口上調用this.Show()this.Hide() 然后我可以拿到手柄,但是窗口上的窗口瞬間閃爍(丑陋!)。

有誰知道強制創建WPF窗口的方法? 在Windows窗體中,這就像訪問Form.Handle屬性一樣簡單。

編輯:我最終選擇了Chris Taylor的答案。 在這里它是,如果它幫助其他人:

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

使用WindowInteropHelper.EnsureHandle ,它完全符合您的需要。

一種選擇是將窗口狀態設置為最小化,而不是在顯示窗口之前顯示在任務欄中。 嘗試這樣的事情。

  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;

如果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

我遇到了同樣的問題並且接受了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編譯代碼,但是在安裝了更高運行時版本的系統(即Windows 8及更高版本)上的.NET運行時4.0上運行它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM