繁体   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