Позиционирование дочернего wpf окна в родительском приложении
Всем привет!
Есть форма на wpf, которая интегрируется в стороннее приложение, в моем случае POWERPOINT.
Все это выглядит так:
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public partial class MainWindow : Window
{
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
private static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
[DllImport("user32")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public const int GWL_EXSTYLE = -20;
public const int WS_EX_LAYERED = 0x80000;
public const int WS_EX_TRANSPARENT = 0x20;
public const int LWA_ALPHA = 0x2;
public const int LWA_COLORKEY = 0x1;
public HwndSource hwnd;
public MainWindow()
{
InitializeComponent();
}
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, int dwNewLong)
{
if (Environment.Is64BitOperatingSystem)
return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong));
else
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
private void Window_ContentRendered(object sender, EventArgs e)
{
this.hwnd = PresentationSource.FromVisual(this) as HwndSource;
if (this.hwnd != null)
{
Process hostProcess = Process.GetProcessesByName("POWERPOINT").FirstOrDefault();
if (hostProcess != null)
{
IntPtr hostHandle = hostProcess.MainWindowHandle;
IntPtr guestHandle = this.hwnd.Handle;
SetWindowLong(hostHandle, GWL_EXSTYLE, (IntPtr)(GetWindowLong(hostHandle, GWL_EXSTYLE) ^ WS_EX_LAYERED));
SetLayeredWindowAttributes(hostHandle, 0, 200, LWA_ALPHA);
SetParent(guestHandle, hostHandle);
this.SetFormPosition();
}
}
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
Window_ContentRendered(sender, e);
}
private void SetFormPosition()
{
int CursorX = System.Windows.Forms.Cursor.Position.X;
int CursorY = System.Windows.Forms.Cursor.Position.Y;
// DpiScale dpi = VisualTreeHelper.GetDpi(new Control());
// double Position_X = CursorX / dpi.DpiScaleX;
// double Position_Y = CursorY / dpi.DpiScaleY;
// Пробовал и так
SetWindowPos(this.hwnd.Handle, IntPtr.Zero, (int)CursorX, (int)CursorY, 0, 0, 0x0001);
// И так тоже
//this.Left = CursorX;
//this.Top = CursorY;
// И еще вариант
//RECT rectParent;
//if (GetWindowRect((IntPtr)PowerPointProvider.Application.HWND, out rectParent))
//{
//this.Left = System.Windows.Forms.Cursor.Position.X - rectParent.Left;
//this.Top = System.Windows.Forms.Cursor.Position.Y - rectParent.Top;
//}
}
}
Форма удачно внедряется в родительское приложение. Возникли проблемы с позиционированием формы. Если окно родительского приложения развернуто во весь экран, то позиционирование срабатывает корректно. Но, если, родительское приложение выходит из полноэкранного режима, положение дочерней формы корректно задать не выходит. Перемещая родительское окно, при постоянных координатах дочерней формы, ее положение постоянно меняется.
Пример:
Родительское окно находится в полноэкранном режиме. Внедряем в него дочернее, устанавливаем координаты x=0, y=0 - дочерняя форма находится в левом верхнем углу родителя. Корректно, как и должно быть.
Размер родительского окна изменил пользователь ( НО левый верхний угол приложения все еще расположен в левом верхнем углу экрана). Внедряем в него дочернее окно, устанавливаем координаты x=0, y=0 Дочерняя форма оказывается примерно по середине родительского окна.
Родительское окно находится в полноэкранном режиме. Внедряем в него дочернее, устанавливаем координаты равные координатам курсора в данный момент - дочерняя форма располагается согласно координатам курсора. Корректно, как и должно быть.
Размер родительского окна изменил пользователь, положение окна так же изменено. Внедряем в него дочернее окно, устанавливаем координаты равные координатам курсора в данный момент - дочерняя форма переходит в координаты близко не похожие в координаты мыши (бывает уходит за границы родителя откуда до нее не достучаться.).
P.S. Во всех примерах, при условии, что родительское окно находится НЕ в полноэкранном режиме, перемещение окна родителя, влечет за собой изменение положения формы при тех же координатах.
P.S.S. Форма представляет собой меню которое открывается при клике на элемент слайда (при этом положение формы == положению мыши) и закрывается при потере фокуса.
Подскажите, что я упустил. Возможно кто-то из Вас знает более корректный метод по внедрению кастомных форм в приложение PowerPoint, а именно в рабочую область Pane - 2.
Спасибо!