在 WPF 应用程序中嵌入 Unity3D 应用程序
Embed Unity3D app inside WPF application
我想在 WPF 中开发一个新的 CAD 软件而不是使用 WPF 3D,是否可以使用 Unity3D 作为我的图形引擎,它能够根据我的数据旋转、平移、缩放和查看 3D 图形对象WPF 中的对象?
我问这个问题的原因是,Unity 是一个游戏引擎,它使用 C# 作为脚本,但它不提供任何来自 WPF 应用程序的集成(将 Unity 嵌入到 WPF 中)。
我在unity论坛上问了这个问题,找不到好的答案,所以问更多的人。
这可以做到,但值得注意的是它只适用于 Windows。
以前很难做到这一点,但 Unity 最近 (4.5.5p1) 向 Unity 应用程序添加了 -parentHWND
command that can be used to embed its program into another program. All you have to do is build your Unity app, then from WPF, start it with the Process
API. You can then pass the -parentHWND
参数。
process.StartInfo.FileName = "YourUnityApp.exe";
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.ToInt32() + " " + Environment.CommandLine;
对于两者之间的通信,您可以使用 TCP 或 。
下面是来自 Unity 网站的嵌入代码的完整示例。你可以获得整个项目here。确保将 Unity 的构建 exe 文件命名为 "UnityGame.exe",然后将其放在与 WPF exe 程序相同的目录中。
namespace Container
{
public partial class Form1 : Form
{
[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);
public Form1()
{
InitializeComponent();
try
{
process = new Process();
process.StartInfo.FileName = "UnityGame.exe";
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.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(panel1.Handle, WindowEnum, IntPtr.Zero);
unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
}
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, panel1.Width, panel1.Height, true);
ActivateUnityWindow();
}
// Close Unity application
private void Form1_FormClosed(object sender, FormClosedEventArgs 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();
}
}
}
我想在 WPF 中开发一个新的 CAD 软件而不是使用 WPF 3D,是否可以使用 Unity3D 作为我的图形引擎,它能够根据我的数据旋转、平移、缩放和查看 3D 图形对象WPF 中的对象?
我问这个问题的原因是,Unity 是一个游戏引擎,它使用 C# 作为脚本,但它不提供任何来自 WPF 应用程序的集成(将 Unity 嵌入到 WPF 中)。
我在unity论坛上问了这个问题,找不到好的答案,所以问更多的人。
这可以做到,但值得注意的是它只适用于 Windows。
以前很难做到这一点,但 Unity 最近 (4.5.5p1) 向 Unity 应用程序添加了 -parentHWND
command that can be used to embed its program into another program. All you have to do is build your Unity app, then from WPF, start it with the Process
API. You can then pass the -parentHWND
参数。
process.StartInfo.FileName = "YourUnityApp.exe";
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.ToInt32() + " " + Environment.CommandLine;
对于两者之间的通信,您可以使用 TCP 或
下面是来自 Unity 网站的嵌入代码的完整示例。你可以获得整个项目here。确保将 Unity 的构建 exe 文件命名为 "UnityGame.exe",然后将其放在与 WPF exe 程序相同的目录中。
namespace Container
{
public partial class Form1 : Form
{
[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);
public Form1()
{
InitializeComponent();
try
{
process = new Process();
process.StartInfo.FileName = "UnityGame.exe";
process.StartInfo.Arguments = "-parentHWND " + panel1.Handle.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(panel1.Handle, WindowEnum, IntPtr.Zero);
unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
}
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, panel1.Width, panel1.Height, true);
ActivateUnityWindow();
}
// Close Unity application
private void Form1_FormClosed(object sender, FormClosedEventArgs 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();
}
}
}