Posted this in Answers, but got no response, not sure if this is the more appropriate place:
I downloaded the EmbeddedWindow.zip linked in -parentHWND option on the command line info page: Unity - Manual: Command-line arguments
I followed the ReadMe exactly:
Open Unity project
Build Windows Standalone application to Export directory, and name the executable as Child.exe
Run Container.exe in Export directory
You should see Windows Standalone application running inside Container application
I also just downloaded Unity 4.6.0f3.
But it doesn’t work. When I run Container.exe, it pops up the start page, where I choose Windowed and 640x480 resolution, but when I click the Play! button, it just opens in its own Window, not inside the Container.exe app (which is running).
Is this even working? Information on it seems scarce on the forums here and on the web. Has anyone successfully used this?
It also seems weird that the example appends the Container.exe file location to the arguments:
That’s what you can expect.
It’s not possible to run an other exe embedded in a screen (like in a VM).
The information you need to check is “Process”.
See here (e.g.):
That’s not what the example, provided by Unity, is doing. It is only setting window parenting.
Anyway, playing around more, I solved my problem. Apparently, this feature is only available in 4.5.5p1. It is not in 4.6.0. I installed 4.5.5p1, and the unity player correctly shows up on the form of the other application.
The bummer is that going back to 4.5.5p1 seems to have wiped out my entire project.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace RunExeInernal
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hwc, IntPtr hwp);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Process calcProc = Process.Start("calc.exe");
Thread.Sleep(500); // give the process some time to start
calcProc.WaitForInputIdle();
SetParent(calcProc.MainWindowHandle, this.Handle);
}
private void button2_Click(object sender, EventArgs e)
{
Process npProc = Process.Start("notepad.exe");
Thread.Sleep(400); // give the process some time to start
npProc.WaitForInputIdle();
SetParent(npProc.MainWindowHandle, this.Handle);
}
}
}
That might work, and allow me to use the latest Unity. I’ll give it a try. Although in other tests, MainWindowHandle isn’t always reliable, I should be able to find it by enumerating the desktop windows.
In case anyone’s interested, the thing I’m using this for is an application that implements a standard Windows user interface and Unity inside a separate window that puts a custom border around the Unity window. I could run the Unity as popup, always find it and move it along with my window, and add a bunch of code to make sure it always appears above the custom border window, etc. But setting the Unity window as a child of the custom border window is just much easier when moving the window around, switching between applications, minimizing, etc.
Alright, SetParent is working. One thing I noticed is that in the EmbeddedExample.zip provided by unity, if I run my Unity scene, it crashes when closing. So I fixed that too. I was also able to restore my project lost when switching versions around by deleting the Library folder and re-loading it twice. I then committed the changes I had to version control (won’t make the mistake again of not doing that before switching Unity versions).
Here’s a breakdown of what I did. This more or less gives the same behavior of -parentHWND in versions that don’t have it. Most of these functions are Win32 functions, so you can either P/Invoke them or use C++ or other unmanaged code:
In the window that hosts (is the parent of) the Unity window, when you want to launch the Unity app:
Call the SetWinEventHook function and create an out-of-context hook for EVENT_OBJECT_CREATE
Start up the process, use the -popupwindow argument, and keep a copy of the handle
In the event callback/delegate:
I used the undocumented Win32 IsTopLevelWindow function to filter out a bunch of windows
Test the window name (GetWindowText) for the name of the Unity application you’re looking for (it’s the name seen at the top when you run the standalone player without -popupwindow)
When found, call SetParent, setting your window as the parent
Call MoveWindow to place it where you want it on the parent
Unhook the event hook
Cleanup. The Unity window doesn’t like to close with another app as the parent for some reason - even if I closed it while my app was still running. It would crash, and in different locations each time.
I put this code in OnFormClosing for my window containing the Unity window.
Call ShowWindow(SW_HIDE) to hide the window so it isn’t seen jumping to the desktop
Call SetParent again setting it to null (desktop)
Call PostMessage to the Unity window with message WM_SYSCOMMAND, wParam = SC_CLOSE to close the Unity window
All in all, it works. The Unity window follows my parent when it moves, minimizes when it minimizes, is always “on top” of my window, etc. Everything you’d expect from a child window. Keep in mind, it still need focus to get keyboard events, etc.
EDITED: Working on this some more, I found a way to close it without the process staying around.
The solution I ended up with (detailed in my last post) is essentially application agnostic. Although Unity did require specific commands to shut down properly.
I would assume it would all work the same with Unity 5, although I can’t upgrade at the present time to check if shutdown works the same.