欢迎来到Introzo百科
Introzo百科
当前位置:网站首页 > 技术 > C# winform嵌入unity3D

C# winform嵌入unity3D

日期:2023-10-06 15:04

-->

  最近在做一个项目,需要winform嵌入Unity的功能。由于我从未接触过这种类型的嵌入,所以我在网上搜索。一种方法是 UnityWebPlayer 插件。我开始思考了一段时间,但很快我发现,5.4版本之后,这种方法就会被淘汰,所以果断放弃。后来我探索了新的方法,看到了另一种使用代码的方法,就开始修修补补。经过修补,发现也有问题,但是没有解决办法,于是就想出了这篇文章。

  问题:winform中操作unity时鼠标没有反应。

  对比:两台机器,A:win7是老古董,1440*900像素,B:win10是新技术,1920*1080像素。

  结论:在A机上不行,但在B机上运行良好。

  原因:屏幕分辨率是罪魁祸首。 Unity的程序是1920*1080。放在A上可能会覆盖unity自身的操作,导致没有效果。

  解决办法:unity程序默认启动设置是全屏(去掉边框的那种)。

  这个问题看似很容易解决,但是作为一个新手,我花了两天时间摆弄它,呃...一开始我以为是系统、插件、参考文献等的问题。 ,但是后来一一排除,原来是解决了……接下来我们看一下主要的实现代码。

使用系统;
使用 System.Collections.Generic;
使用系统.诊断;
使用 System.Linq;
使用 System.Runtime.InteropServices;
使用 System.Text;
使用 System.Threading;
使用 System.Windows.Forms; 命名空间演示
{
公开课 exetowinform
{
EventHandler appIdleEvent = null;
控制ParentCon = null;
字符串 strGUID = ""; public exetowinform(Control C, string Titlestr)
{
appIdleEvent = new EventHandler(Application_Idle);
父Con = C;
strGUID = Titlestr;
} ///
/// 打开属性AppFilename指向的应用程序并将其嵌入到此容器中
///

public IntPtr Start(string FileNameStr)
{
if (m_AppProcess != null)
{
停止();
}
试试
{
ProcessStartInfo info = new ProcessStartInfo(FileNameStr);
info.UseShellExecute = true;
info.WindowStyle = ProcessWindowStyle.Minimized;
m_AppProcess = System.Diagnostics.Process.Start(info);
m_AppProcess.WaitForInputIdle();
Application.Idle += appIdleEvent;
}
抓住
{
if (m_AppProcess != null)
{
if (!m_AppProcess.HasExited)
m_AppProcess.Kill();
m_AppProcess = null;
}
}
return m_AppProcess.Handle;
} ///
///确保应用程序嵌入此容器
///

///
///
void Application_Idle(对象发送者, EventArgs e)
{
if (this.m_AppProcess == null || this.m_AppProcess.HasExited)
{
this.m_AppProcess = null;
Application.Idle -= appIdleEvent;
返回; } Thread.Sleep();//这里加阻塞,时间可以大一些
Application.DoEvents();
if (m_AppProcess.MainWindowHandle == www.introzo.com)
返回;
Application.Idle -= appIdleEvent;
EmbedProcess(m_AppProcess, ParentCon);
}
///
/// 当应用程序结束运行时,应清除此处的标志
///

///
///
void m_AppProcess_Exited(对象发送者, EventArgs e)
{
m_AppProcess = null;
}
///
/// 关闭属性AppFilename
指向的应用程序 ///

public void Stop()
{
if (m_AppProcess != null)// && m_AppProcess.MainWindowHandle != www.introzo.com)
{
试试
{
if (!m_AppProcess.HasExited)
m_AppProcess.Kill();
}
catch(异常)
{
}
m_AppProcess = null;
}
}
#region 属性
///
/// 申请流程
///

进程 m_AppProcess = null; ///
/// 标识内嵌程序是否已经启动
///

公共 bool IsStarted { 获取 { return (this.m_AppProcess != null); } } #endregion 属性 #region Win32 API
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
CharSet = CharSet.Unicode,ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
私有静态 extern 长 GetWindowThreadProcessId(long hWnd, long lpdwProcessId); [DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", SetLastError = true)]
私有静态 extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
私有静态 extern long GetWindowLong(IntPtr hwnd, int nIndex); 公共静态 IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
{
if (IntPtr.Size == )
{
返回 SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
}
返回 SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = www.introzo.com)]
公共静态 extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = www.introzo.com)]
公共静态 extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", SetLastError = true)]
私有静态外部长SetWindowPos(IntPtr hwnd,长hWndInsertAfter,长x,长y,长cx,长cy,长wFlags); [DllImport("user32.dll", SetLastError = true)]
私有静态 extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint); [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
私有静态 extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam); [DllImport("user32.dll", SetLastError = true)]
私有静态 extern IntPtr GetParent(IntPtr hwnd); [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
静态 extern bool ShowWindow(IntPtr hWnd, int nCmdShow);私有常量 int SWP_NOOWNERZORDER = 0x200;
私有常量 int SWP_NOREDRAW = 0x8;
私有 const int SWP_NOZORDER = 0x4;
私有 const int SWP_SHOWWINDOW = 0x0040;
私有常量 int WS_EX_MDICHILD = 0x40;
私有常量 int SWP_FRAMECHANGED = 0x20;
私有常量 int SWP_NOACTIVATE = 0x10;
私有 const int SWP_ASYNCWINDOWPOS = 0x4000;
私有 const int SWP_NOMOVE = 0x2;
私有 const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-);
私有常量 int WS_VISIBLE = 0x10000000;
私有 const int WM_CLOSE = 0x10;
私有常量 int WS_CHILD = 0x40000000; 私有常量 int SW_HIDE = ; //{隐藏,任务栏上没有最小化图标}
私有常量 int SW_SHOWNORMAL = ; //{以最接近的尺寸和位置显示,激活}
私有常量 int SW_NORMAL = ; //{与SW_SHOWNORMAL相同}
私有常量 int SW_SHOWMINIMIZED = ; //{最小化,激活}
私有常量 int SW_SHOWMAXIMIZED = ; //{最大化,激活}
私有常量 int SW_MAXIMIZE = ; //{与SW_SHOWMAXIMIZED相同}
私有常量 int SW_SHOWNOACTIVATE = ; //{以最接近的尺寸和位置显示,不活动}
私有常量 int SW_SHOW = ; //{与SW_SHOWNORMAL相同}
私有常量 int SW_MINIMIZE = ; //{最小化,不活动}
私有常量 int SW_SHOWMINNOACTIVE = ; //{与SW_MINIMIZE相同}
私有常量 int SW_SHOWNA = ; //{与SW_SHOWNOACTIVATE相同}
私有常量 int SW_RESTORE = ; //{与SW_SHOWNORMAL相同}
私有常量 int SW_SHOWDEFAULT = ; //{与SW_SHOWNORMAL相同}
私有常量 int SW_MAX = ; //{与SW_SHOWNORMAL相同} #endregion Win32 API ///
/// 将指定程序嵌入到指定控件中
///

private void EmbedProcess(流程应用程序,控制控制)
{
// 获取主句柄
if (app == null || app.MainWindowHandle == www.introzo.com || control == null) return;
试试
{
// 把它写成这个形式
SetParent(app.MainWindowHandle, control.Handle);
}
catch(异常)
{ }
试试
{
// 删除边框之类的东西
SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);
SendMessage(app.MainWindowHandle, WM_SETTEXT, www.introzo.com, strGUID);
}
catch(异常)
{ }
试试
{
// 移动窗口使其覆盖在本窗口上
MoveWindow(app.MainWindowHandle, , , control.Width, control.Height, true);
}
catch(异常)
{ }
}
[DllImport("User32.dll", EntryPoint = "SendMessage")]
私有静态 extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam); const int WM_SETTEXT = 0x000C;
}
}

拨打方式:

//panel1是表单中的控件名称
exetowinform fr = new exetowinform(panel1, "");
//打开unity生成的exe文件
fr.Start(@"E:\Text.exe"); -->