簡體   English   中英

如何在外部 Win32 應用程序窗口上添加 WPF 覆蓋?

[英]How can I add a WPF overlay over an external Win32 application's window?

我正在嘗試將 WPF 窗口附加為外部應用程序(例如記事本)的子窗口以提供疊加層。 在研究了我可以在 SO 和 MSDN 上找到的所有答案后,我已經在我的 WPF 應用程序運行時在記事本的角落上創建了一個堅實的覆蓋層。 然而,

  • 一旦記事本獲得焦點,覆蓋就會消失,
  • 以及在記事本上顯示的疊加層,疊加層也單獨顯示為一個窗口
  • 記事本上的覆蓋層不會接收任何 MouseMove 事件(但單獨的窗口會。

這是演示該問題的最小示例:

覆蓋.xaml

<Window x:Class="WindowControlTest.Overlay"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="300"
        Opacity="1"
        Background="Azure"
        MouseMove="Window_MouseMove"
        GotFocus="Window_GotFocus"
        Loaded="Window_Loaded"
        Title="Overlay" 
        WindowStyle="None"
        >
</Window>

覆蓋.xaml.cs

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Interop;

namespace WindowControlTest
{

    public partial class Overlay : Window
    {
        IntPtr m_ParentHwnd;
        HwndSource m_HwndSource;

        public Overlay(IntPtr parentHwnd)
        {
            InitializeComponent();
            m_ParentHwnd = parentHwnd;
        }

        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            Console.WriteLine("Overlay.Window_MouseMove: " + e.GetPosition(this));
        }

        private void Window_GotFocus(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("Overlay.Window_GotFocus");
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            HwndSourceParameters parameters = new HwndSourceParameters();
            parameters.WindowStyle = (int) (WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD);
            parameters.SetPosition(0, 0);
            parameters.UsesPerPixelOpacity = true;
            parameters.SetSize((int)Width, (int)Height);
            parameters.ParentWindow = m_ParentHwnd;
            m_HwndSource = new HwndSource(parameters);
            m_HwndSource.CompositionTarget.BackgroundColor = Colors.Aqua;
            m_HwndSource.RootVisual = (Visual)Content;
        }
    }
}

主窗口.xaml

<Window x:Class="WindowControlTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Loaded="OnLoaded"
        >

    <StackPanel>
        <Label x:Name="stateLabel">Label</Label>
    </StackPanel>
</Window>

MainWindow.xaml.cs - 查找和處理記事本並創建Overlay

using System;
using System.Text;
using System.Windows;

namespace WindowControlTest
{
    public partial class MainWindow : Window
    {
        private IntPtr m_TargetHwnd;
        private Overlay m_Overlay;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            processWindows();

            if (m_TargetHwnd != IntPtr.Zero)
            {
                m_Overlay = new Overlay(m_TargetHwnd);
                m_Overlay.Show();
            }
        }

        private void processWindows()
        {
            Win32.EnumWindows(delegate(IntPtr wnd, IntPtr param)
            {
                String text = GetWindowText(wnd);
                Console.WriteLine("Window: " + text);
                if (text.Contains("Notepad"))
                {
                    m_TargetHwnd = wnd;
                }
                return true;
            }, IntPtr.Zero);
        }

        public static string GetWindowText(IntPtr hWnd)
        {
            int size = Win32.GetWindowTextLength(hWnd);
            if (size++ > 0)
            {
                var builder = new StringBuilder(size);
                Win32.GetWindowText(hWnd, builder, builder.Capacity);
                return builder.ToString();
            }
            return String.Empty;
        }
    }
}

(注意:許多 SO 問題解決了一個類似但不同的問題,例如如何將 Win32 窗口設置為 WPF 窗口的所有者?假設我可以控制 Win32 窗口的源代碼,就像我在 MSDN 上可以找到的示例一樣.)

我認為您走錯了路,而不是讓您的覆蓋層成為記事本窗口的子級,您應該嘗試通過 HwndHost 使記事本成為主窗口的子級,然后將覆蓋層保持在主機上方。

這是我的博客文章,介紹了我編寫的一個庫,用於在 HwndHost 托管的任何 hwnd 上分層 WPF 裝飾器。 一個簡單的 Web 瀏覽器演示如下所示:

快照

暫無
暫無

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

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