最近在开发的一个项目需要用QT调用Unity的应用。想到的办法就是启动Unity应用,嵌入到QT应用中。
由于Unity应用加载需要时间,而且无法隐藏加载窗口(本人不熟悉unity开发)。因此采用外部调用的方式加载unity应用。
一、QT 调用Unity程序CreateProcess
STARTUPINFO si; si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = STARTF_USESHOWWINDOW| STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.cbReserved2 = NULL; si.lpReserved2 = NULL; std::wstring str = path.toStdWString(); BOOL ret = CreateProcess(NULL, (LPTSTR)str.c_str(), NULL, NULL, FALSE, CREATE_SUSPENDED|CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
此时untiy.exe以进程挂起的方式隐藏创建,且没有新的窗口。
二、第一次显示的时候可以调用解挂,并设置unity.exe与应用程序的窗口关系
::ResumeThread((HANDLE)pi.hThread); HWND childHwnd = NULL; while (true) { childHwnd = FindWindowA(NULL, m_strExeWndName.c_str()); if (childHwnd != NULL) { break; } } //2、延时,这个很重要,一定要大于50 Sleep(3200);
//4、设置父窗口 HWND parentHwnd = (HWND)ui.mWidget->winId(); SetParent(childHwnd, parentHwnd); //5、设置窗口位置 SetWindowPos(childHwnd, HWND_TOPMOST, 0, 0, nWidth, nHeight, SWP_FRAMECHANGED);
三、关闭进程 TerminateProcess(pi.hProcess, 0);//终止进程 ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess);
四、设置Unity窗口属性
unity窗口是以windows形式build的。此时会带有边框、标题栏。需要隐藏边框和标题栏。
此处代码可参见:https://blog.csdn.net/ldy597321444/article/details/86595786
注意:unity窗口如果是全屏创建的,此时到了QT应用中,不能自适应窗口的大小。需要保证unity窗口的大小和QT中展示Unity应用部分的窗口大小一致。
STARTF_USESIZE| STARTF_USEPOSITION两个属性,并不能更改Unity窗口的大小。详见MSDN。
研究过程记录:
1、首先想到的是隐藏Unity程序的边框,但是本人对于Unity不熟悉,仅隐藏了脚本加载后的边框,没有隐藏掉加载时的边框;
2、不能使用QT通过CreateProcess调用进程后,再修改unity窗口的属性。此时,已经显示并获取到了Unity窗口的属性。方法1和2,均会产生unity加载窗口,且加载后会有位置的移动。因此有了第三种方案,在加载进程时改变窗口状态。
3、CreateProcess时,使用线程挂起的方式,并设置窗口的隐藏。