加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 将WPF窗口附加到另一个进程的窗口

发布时间:2020-12-15 20:55:43 所属栏目:百科 来源:网络整理
导读:我想写一个 WPF应用程序,它停靠在另一个进程中运行的应用程序(这是我无法控制的第三方应用程序).理想情况下,我希望能够定义应用程序是在左侧还是右侧停靠. 这是我想要做的一个例子: 我试图实现以下两个例子但没有成功. Attach window to window of another
我想写一个 WPF应用程序,它停靠在另一个进程中运行的应用程序(这是我无法控制的第三方应用程序).理想情况下,我希望能够定义应用程序是在左侧还是右侧停靠.

这是我想要做的一个例子:

Docked example

我试图实现以下两个例子但没有成功.

Attach window to window of another process – Button_Click给出以下错误:

error image

Attach form window to another window in C# – Button_Click_1将其停靠在标题栏上,但我看不到整个应用:

App docked

以下是代码:

namespace WpfApplicationTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    [DllImport("user32.dll")]
    public static extern int SetWindowLong(IntPtr hWnd,int nIndex,int dwNewLong);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd,int nIndex);

    [DllImport("user32.dll",SetLastError = true)]
    private static extern IntPtr SetParent(IntPtr hWndChild,IntPtr hWndNewParent);

    public static int GWL_STYLE = -16;
    public static int WS_CHILD = 0x40000000;

    [DllImport("user32")]
    private static extern bool SetWindowPos(
        IntPtr hWnd,IntPtr hWndInsertAfter,int x,int y,int cx,int cy,uint uFlags);

    private IntPtr _handle;
    private void SetBounds(int left,int top,int width,int height)
    {
        if (_handle == IntPtr.Zero)
            _handle = new WindowInteropHelper(this).Handle;

        SetWindowPos(_handle,IntPtr.Zero,left,top,width,height,0);
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender,RoutedEventArgs e)
    {
        Process hostProcess = Process.GetProcessesByName("notepad").FirstOrDefault();
        IntPtr hostHandle = hostProcess.MainWindowHandle;

        //MyWindow window = new MyWindow();
        this.ShowActivated = true;

        HwndSourceParameters parameters = new HwndSourceParameters();

        parameters.WindowStyle = 0x10000000 | 0x40000000;
        parameters.SetPosition(0,0);
        parameters.SetSize((int)this.Width,(int)this.Height);
        parameters.ParentWindow = hostHandle;
        parameters.UsesPerPixelOpacity = true;
        HwndSource src = new HwndSource(parameters);

        src.CompositionTarget.BackgroundColor = Colors.Transparent;
        src.RootVisual = (Visual)this.Content;
    }

    private void Button_Click_1(object sender,RoutedEventArgs e)
    {
        Process hostProcess = Process.GetProcessesByName("notepad").FirstOrDefault();
        if (hostProcess != null)
        {
            Hide();

            //this.WindowStyle;

            //new WindowInteropHelper(this).SetBounds(0,BoundsSpecified.Location);

            //SetWindowPos(new WindowInteropHelper(this).Handle,0);
            SetBounds(0,0);

            IntPtr hostHandle = hostProcess.MainWindowHandle;
            IntPtr guestHandle = new WindowInteropHelper(this).Handle;

            SetWindowLong(guestHandle,GWL_STYLE,GetWindowLong(guestHandle,GWL_STYLE) | WS_CHILD);
            SetParent(guestHandle,hostHandle);

            Show();
        }
    }
}

解决方法

您的实现是完全错误的,您正试图将您的窗口设置为要捕捉的窗口的子窗口.

我写了一个小帮手类,用它的标题捕捉到另一个窗口,我希望这有帮助.

WindowSnapper.cs

public class WindowSnapper
{
    private struct Rect
    {
        public int Left { get; set; }
        public int Top { get; set; }
        public int Right { get; set; }
        public int Bottom { get; set; }

        public int Height
        {
            get { return Bottom - Top; }
        }

        public static bool operator !=(Rect r1,Rect r2)
        {
            return !(r1 == r2);
        }

        public static bool operator ==(Rect r1,Rect r2)
        {
            return r1.Left == r2.Left && r1.Right == r2.Right && r1.Top == r2.Top && r1.Bottom == r2.Bottom;
        }
    }

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hwnd,ref Rect rectangle);

    private DispatcherTimer _timer;
    private IntPtr _windowHandle;
    private Rect _lastBounds;
    private Window _window;
    private string _windowTitle;

    public WindowSnapper(Window window,String windowTitle)
    {
        _window = window;
        _window.Topmost = true;
        _windowTitle = windowTitle;

        _timer = new DispatcherTimer();
        _timer.Interval = TimeSpan.FromMilliseconds(10);
        _timer.Tick += (x,y) => SnapToWindow();
        _timer.IsEnabled = false;
    }

    public void Attach()
    {
        _windowHandle = GetWindowHandle(_windowTitle);
        _timer.Start();
    }

    public void Detach()
    {
        _timer.Stop();
    }

    private void SnapToWindow()
    {
        var bounds = GetWindowBounds(_windowHandle);

        if (bounds != _lastBounds)
        {
            _window.Top = bounds.Top;
            _window.Left = bounds.Left - _window.Width;
            _window.Height = bounds.Height;
            _lastBounds = bounds;
        }
    }

    private Rect GetWindowBounds(IntPtr handle)
    {
        Rect bounds = new Rect();
        GetWindowRect(handle,ref bounds);
        return bounds;
    }

    private IntPtr GetWindowHandle(string windowTitle)
    {
        foreach (Process pList in Process.GetProcesses())
        {
            if (pList.MainWindowTitle.Contains(windowTitle))
            {
                return pList.MainWindowHandle;
            }
        }

        return IntPtr.Zero;
    }
}

用法示例:

public partial class MainWindow : Window
{
    private WindowSnapper _snapper;

    public MainWindow()
    {
        InitializeComponent();

        _snapper = new WindowSnapper(this,"Notepad");
        _snapper.Attach();
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读