gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 12:42:45 24 4
gpt4 key购买 nike

我想编写一个 WPF 应用程序,它停靠在另一个进程中运行的应用程序(这是我无法控制的第 3 方应用程序)。理想情况下,我希望能够定义应用停靠在左侧还是右侧。

这是我想做的一个例子:

Docked example

我已尝试实现以下 2 个示例,但均未成功。

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, 0, 0, 0, BoundsSpecified.Location);

//SetWindowPos(new WindowInteropHelper(this).Handle, IntPtr.Zero, 0, 0, 0, 0, 0);
SetBounds(0, 0, 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();
}
}

关于c# - 将 WPF 窗口附加到另一个进程的窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32806280/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com