我是WPF的新手,我正在尝试从the unity docs重新创建EmbeddedWindow示例的功能,它解释了如何使用命令行和-parentHWND在WPF窗口内启动独立的统一窗口。
示例使用此行(在WinForm中?):
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.ToInt32() + " " + Environment.CommandLine;
我试图将其替换为:
process.StartInfo.Arguments = "-parentHWND " + canvas1.Parent + " " + Environment.CommandLine;
因为我不知道该怎么做。
当我尝试在WPF中启动程序时,我收到错误:“无法创建窗口”
有人可以给我一个代码示例,说明如何在WPF中正确使用此命令行吗?如何按照文档要求从MDL调用SetParent?
答案 0 :(得分:0)
您必须使用HwndHost类。这是我正在使用的代码:
class UnityHwndHost : HwndHost
{
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", SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint processId);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")] // TODO: 32/64?
internal static extern IntPtr GetWindowLongPtr(IntPtr hWnd, Int32 nIndex);
internal const Int32 GWLP_USERDATA = -21;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr PostMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
internal const UInt32 WM_CLOSE = 0x0010;
private string programName;
private string arguments;
private Process process = null;
private IntPtr unityHWND = IntPtr.Zero;
public UnityHwndHost(string programName, string arguments = "")
{
this.programName = programName;
this.arguments = arguments;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
Debug.WriteLine("Going to launch Unity at: " + this.programName + " " + this.arguments);
process = new Process();
process.StartInfo.FileName = programName;
process.StartInfo.Arguments = arguments + (arguments.Length == 0 ? "" : " ") + "-parentHWND " + hwndParent.Handle;
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForInputIdle();
int repeat = 50;
while (unityHWND == IntPtr.Zero && repeat-- > 0)
{
Thread.Sleep(100);
EnumChildWindows(hwndParent.Handle, WindowEnum, IntPtr.Zero);
}
if (unityHWND == IntPtr.Zero)
throw new Exception("Unable to find Unity window");
Debug.WriteLine("Found Unity window: " + unityHWND);
repeat += 150;
while ((GetWindowLongPtr(unityHWND, GWLP_USERDATA).ToInt32() & 1) == 0 && --repeat > 0)
{
Thread.Sleep(100);
Debug.WriteLine("Waiting for Unity to initialize... "+repeat);
}
if (repeat == 0)
{
Debug.WriteLine("Timed out while waiting for Unity to initialize");
}
else
{
Debug.WriteLine("Unity initialized!");
}
return new HandleRef(this, unityHWND);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
if (unityHWND != IntPtr.Zero)
throw new Exception("Found multiple Unity windows");
unityHWND = hwnd;
return 0;
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
Debug.WriteLine("Asking Unity to exit...");
PostMessage(unityHWND, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
int i = 30;
while (!process.HasExited)
{
if (--i < 0)
{
Debug.WriteLine("Process not dead yet, killing...");
process.Kill();
}
Thread.Sleep(100);
}
}
}
使用此方法的方式是,首先以XML创建一些容器,然后每当要启动Unity时将其添加为子容器:
UnityDisplay.Child = new UnityHwndHost("UnityApp.exe", "-possibly -other -arguments");