【问题标题】:Unity window inside WPF application (XAML) not resizingWPF 应用程序 (XAML) 中的 Unity 窗口未调整大小
【发布时间】:2022-02-23 23:49:14
【问题描述】:

我正在尝试将统一应用程序 (.exe) 集成到 WPF XAML 应用程序中。我设法让统一窗口在 WPF 窗口内打开,但它卡在窗口的左上角,并且在我调整 WPF 窗口大小时不会调整大小。

这是我的代码,(统一应用程序称为 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();
        }
    }
}

我尝试将统一窗口放置在内容演示器中,如下所示:

<ContentPresenter x:Name="unityContent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

</ContentPresenter>

但调整大小仍然不起作用。

我在很多地方都阅读过使用WindowsFormsHost,但由于这不是表单应用程序,所以这不起作用。 谁能告诉我哪里出错了? 感谢您的宝贵时间。

编辑: 我设法让带有统一窗口的网格通过更改来调整大小: MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);

MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);

但是现在,在第一次调整大小后,统一窗口的两侧出现了空白。我需要它来填充所有可用空间。请看图。

【问题讨论】:

    标签: c# wpf unity3d xaml resize


    【解决方案1】:

    我通过做两件事解决了这个问题:

    1. 通过更改MoveWindow(_unityHWND, 0, 0, (int)UnityContent.Width, (int)UnityContent.Height, true);

    MoveWindow(_unityHWND, 0, 0, (int)UnityContent.ActualWidth, (int)UnityContent.ActualHeight, true);

    1. unity 窗口与 WPF 窗口的比例不同,所以我不得不在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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 2013-11-05
      • 2011-03-30
      • 1970-01-01
      • 2010-10-04
      • 2012-10-04
      相关资源
      最近更新 更多