WPF 应用程序 (XAML) 中的 Unity window 未调整大小
Unity window inside WPF application (XAML) not resizing
我正在尝试将统一应用程序 (.exe) 集成到 WPF XAML 应用程序中。我已经设法让 unity window 在 WPF window 中打开,但它卡在 window 的左上角并且在我调整 WPF [=] 大小时不调整大小48=].
这是我的代码,(统一应用程序称为 unityWindow.exe):
MainWindow.xaml
<Window x:Class="UnityApplicationIntegration.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UnityApplicationIntegration"
mc:Ignorable="d"
Title="MainWindow" MinHeight="488" MinWidth="815">
<Grid x:Name="unityContent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Threading;
namespace UnityApplicationIntegration
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private Process _process;
private IntPtr _unityHWND = IntPtr.Zero;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
//Frame p = MainWindow.Instance.floatingFrame;
Grid UnityContent;
bool initialized = false;
public MainWindow()
{
InitializeComponent();
UnityContent = unityContent;
//MainWindow.Instance.MainWindowClosing += Application_Exit;
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += attemptInit;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
void attemptInit(object sender, EventArgs e)
{
if (initialized)
return;
HwndSource source = (HwndSource)HwndSource.FromVisual(UnityContent);
Debug.WriteLine("attempting to get handle...");
if (source == null)
{
Debug.WriteLine("Failed to get handle source");
return;
}
IntPtr hWnd = source.Handle;
try
{
_process = new Process();
_process.StartInfo.FileName = "UnityWindow.exe";
_process.StartInfo.Arguments = "-parentHWND " + hWnd.ToInt32() + " " + Environment.CommandLine;
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.CreateNoWindow = true;
_process.Start();
_process.WaitForInputIdle();
// Doesn't work for some reason ?!
//hWnd = _process.MainWindowHandle;
EnumChildWindows(hWnd, WindowEnum, IntPtr.Zero);
//unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
Debug.WriteLine("Unity HWND: 0x" + _unityHWND.ToString("X8"));
// TODO: rename. What are the Args?
UnityContentResize(this, EventArgs.Empty);
initialized = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ".\nCheck if Container.exe is placed next to UnityGame.exe.");
}
}
private void ActivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
_unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
private void UnityContentResize(object sender, EventArgs e)
{
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
Debug.WriteLine("RESIZED UNITY WINDOW TO: " + (int)UnityContent.Width + "x" + (int)UnityContent.Height);
ActivateUnityWindow();
}
// Close Unity application
private void ApplicationExit(object sender, EventArgs e)
{
try
{
_process.CloseMainWindow();
Thread.Sleep(1000);
while (!_process.HasExited)
_process.Kill();
}
catch (Exception)
{
}
}
private void UnityContentActivate(object sender, EventArgs e)
{
ActivateUnityWindow();
}
private void UnityContentDeactivate(object sender, EventArgs e)
{
DeactivateUnityWindow();
}
}
}
我试过将统一 window 放在内容展示器中,如下所示:
<ContentPresenter x:Name="unityContent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</ContentPresenter>
但调整大小仍然无效。
我在很多地方都读过要使用 WindowsFormsHost
但由于这不是一个表单应用程序,所以它不起作用。
谁能告诉我哪里出错了?
感谢您的宝贵时间。
编辑:
我设法通过更改 window 来调整网格的大小:
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
至
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);
但是现在,在第一次调整大小后,我在统一 window 的两侧得到空白 space。我需要它来填充所有可用的 space。请看图
我通过两件事解决了这个问题:
- 通过更改
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
到
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);
- unity window 与 WPF window 的规模不同,所以我不得不将以下内容添加到
mainwindow.xaml.cs
double scaleX, scaleY;
if (s != null)
{
scaleX = s.CompositionTarget.TransformToDevice.M11;
scaleY = s.CompositionTarget.TransformToDevice.M22;
}
var actualHeight = (int)UnityContent.ActualHeight * scaleY;
var actualWidth = (int)UnityContent.ActualWidth * scaleX;
MoveWindow(_unityHWND, 0, 0, (int)actualWidth, (int)actualHeight, true);
我正在尝试将统一应用程序 (.exe) 集成到 WPF XAML 应用程序中。我已经设法让 unity window 在 WPF window 中打开,但它卡在 window 的左上角并且在我调整 WPF [=] 大小时不调整大小48=].
这是我的代码,(统一应用程序称为 unityWindow.exe):
MainWindow.xaml
<Window x:Class="UnityApplicationIntegration.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UnityApplicationIntegration"
mc:Ignorable="d"
Title="MainWindow" MinHeight="488" MinWidth="815">
<Grid x:Name="unityContent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Threading;
namespace UnityApplicationIntegration
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private Process _process;
private IntPtr _unityHWND = IntPtr.Zero;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
//Frame p = MainWindow.Instance.floatingFrame;
Grid UnityContent;
bool initialized = false;
public MainWindow()
{
InitializeComponent();
UnityContent = unityContent;
//MainWindow.Instance.MainWindowClosing += Application_Exit;
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += attemptInit;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
void attemptInit(object sender, EventArgs e)
{
if (initialized)
return;
HwndSource source = (HwndSource)HwndSource.FromVisual(UnityContent);
Debug.WriteLine("attempting to get handle...");
if (source == null)
{
Debug.WriteLine("Failed to get handle source");
return;
}
IntPtr hWnd = source.Handle;
try
{
_process = new Process();
_process.StartInfo.FileName = "UnityWindow.exe";
_process.StartInfo.Arguments = "-parentHWND " + hWnd.ToInt32() + " " + Environment.CommandLine;
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.CreateNoWindow = true;
_process.Start();
_process.WaitForInputIdle();
// Doesn't work for some reason ?!
//hWnd = _process.MainWindowHandle;
EnumChildWindows(hWnd, WindowEnum, IntPtr.Zero);
//unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
Debug.WriteLine("Unity HWND: 0x" + _unityHWND.ToString("X8"));
// TODO: rename. What are the Args?
UnityContentResize(this, EventArgs.Empty);
initialized = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ".\nCheck if Container.exe is placed next to UnityGame.exe.");
}
}
private void ActivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
_unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
private void UnityContentResize(object sender, EventArgs e)
{
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
Debug.WriteLine("RESIZED UNITY WINDOW TO: " + (int)UnityContent.Width + "x" + (int)UnityContent.Height);
ActivateUnityWindow();
}
// Close Unity application
private void ApplicationExit(object sender, EventArgs e)
{
try
{
_process.CloseMainWindow();
Thread.Sleep(1000);
while (!_process.HasExited)
_process.Kill();
}
catch (Exception)
{
}
}
private void UnityContentActivate(object sender, EventArgs e)
{
ActivateUnityWindow();
}
private void UnityContentDeactivate(object sender, EventArgs e)
{
DeactivateUnityWindow();
}
}
}
我试过将统一 window 放在内容展示器中,如下所示:
<ContentPresenter x:Name="unityContent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</ContentPresenter>
但调整大小仍然无效。
我在很多地方都读过要使用 WindowsFormsHost
但由于这不是一个表单应用程序,所以它不起作用。
谁能告诉我哪里出错了?
感谢您的宝贵时间。
编辑:
我设法通过更改 window 来调整网格的大小:
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
至
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);
但是现在,在第一次调整大小后,我在统一 window 的两侧得到空白 space。我需要它来填充所有可用的 space。请看图
我通过两件事解决了这个问题:
- 通过更改
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);
到
MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);
- unity window 与 WPF window 的规模不同,所以我不得不将以下内容添加到
mainwindow.xaml.cs
double scaleX, scaleY;
if (s != null)
{
scaleX = s.CompositionTarget.TransformToDevice.M11;
scaleY = s.CompositionTarget.TransformToDevice.M22;
}
var actualHeight = (int)UnityContent.ActualHeight * scaleY;
var actualWidth = (int)UnityContent.ActualWidth * scaleX;
MoveWindow(_unityHWND, 0, 0, (int)actualWidth, (int)actualHeight, true);