2015-09-27 181 views
4

我想编写一个停靠在另一个进程中运行的应用程序的WPF应用程序(这是我无法控制的第三方应用程序)。理想情况下,我希望能够定义应用是在左侧还是右侧停靠。将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, 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(); 
     } 
    } 
} 
+0

你说的 '码头' 究竟是什么意思? –

+0

Dock =连接到 –

+0

的一侧您可以尝试使用短语“snap to”而不是“dock to”来搜索Google。 –

回答

0

你的实现是完全错误的,你试图让你的窗口作为你想要捕捉的窗口的子窗口。

我写了一个小助手类来捕捉另一个窗口的标题,我希望这有助于。

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(); 
    } 
} 
相关问题