Встраивайте приложение Unity3D в WPF *, не занимая всего окна - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь адаптировать код, указанный в этом вопросе: https://stackoverflow.com/a/44059700

, чтобы позволить мне встроить приложение Unity3D в приложение WPF.

Это моя слегка отредактированная версия:

namespace WPFWithUnity
{
public partial class Page1 : Page
{
    [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;

    bool initialized = false;

    public Page1()
    {
        InitializeComponent();

        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(p);

        Console.WriteLine("attempting to get handle...");

        if (source == null) {
            Console.WriteLine("Failed to get handle source");
            return;
        }

        IntPtr hWnd = source.Handle;

        try
        {
            process = new Process();
            process.StartInfo.FileName = "Child.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 ?!
            //unityHWND = process.MainWindowHandle;
            EnumChildWindows(hWnd, WindowEnum, IntPtr.Zero);

            //unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
            Console.WriteLine("Unity HWND: 0x" + unityHWND.ToString("X8"));

            panel1_Resize(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 panel1_Resize(object sender, EventArgs e)
    {
        MoveWindow(unityHWND, 0, 0, (int)p.Width, (int)p.Height, true);
        Console.WriteLine("RESIZED UNITY WINDOW TO: " + (int)p.Width + "x" + (int)p.Height);
        ActivateUnityWindow();
    }

    // Close Unity application
    private void Application_Exit(object sender, EventArgs e)
    {
        try
        {
            process.CloseMainWindow();

            Thread.Sleep(1000);
            while (!process.HasExited)
                process.Kill();
        }
        catch (Exception)
        {

        }
    }

    private void Form1_Activated(object sender, EventArgs e)
    {
        ActivateUnityWindow();
    }

    private void Form1_Deactivate(object sender, EventArgs e)
    {
        DeactivateUnityWindow();
    }
}
}

А вот соответствующая часть XAML:

<Frame Name="floatingFrame" Grid.Row="15" Grid.RowSpan="5" Grid.Column="0" Grid.ColumnSpan="2" Width="640" Height="480" Margin="100,0,0,0" Panel.ZIndex="100" Source="Page1.xaml"/>

Действительно, единственное отличие состоит в том, что я пытаюсь использовать страницу WPF внутри фрейма вместоПанель WinForms (пытается избежать WinForms).Встроенное приложение Unity запускается нормально ... за исключением того, что оно занимает все окно (т. Е. Вы больше не видите элементы управления WPF).

Итак, вопрос: Как заставить приложение Unity оставаться только внутри страницы WPF (которая находится внутри фрейма)?

введите описание изображения здесь

(Y этого XYпроблема заключается в том, что я просто пытаюсь создать трехмерное графическое изображение чего-то внутри приложения WPF.)

Заранее благодарен за любую помощь.

1 Ответ

0 голосов
/ 24 января 2019

Используйте WindowsFormsHost или HwndHost элемент управления в вашем WPF. Hwnd находится в свойстве Handle основного элемента управления. Таким образом, вы можете изменить эту строку, чтобы поместить Unity только в управление хостом.

process.StartInfo.Arguments = "-parentHWND " + hwndHost.Handle.ToInt32() + " " + Environment.CommandLine;

И удалить код, который получает hwnd для плавающего фрейма

HwndSource source = (HwndSource)HwndSource.FromVisual(p);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...