最近在開發的一個項目需要用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時,使用線程掛起的方式,並設置窗口的隱藏。