现在的大型软件启动之后,很可能存在多个进程。如浏览器,每打开一个新的页面,就会启动一个新的进程。为什么会使用多进程,而不是全部使用多线程呢?因为多进程,可以做到完全的隔离,这样的好处是:如果一个页面卡死了,不会干扰到其他页面;在代码层,也少了多页面之间线程变量安全考虑的顾忌了,不用考虑同步异步等操作。
我们在MainUI中嵌入ThirdUI窗口,主要有以下步骤:
主要通过CreateProcess函数来打开第三方进程,并获取进程ID。
HWND CNestWndDlg::OpenProcess()
{
// 进程启动信息
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
// 进程信息
PROCESS_INFORMATION pi = {0};
// 创建进程
if (CreateProcess("C:\\WINDOWS\\system32\\notepad.exe", NULL, NULL, NULL, false, 0, NULL, NULL, &si, &pi))
{
PROCESS_INFO procwin;
procwin.dwProcessId = pi.dwProcessId;
procwin.hWnd = NULL;
// 等待新进程初始化完毕
WaitForInputIdle(pi.hProcess, 5000);
EnumWindows(EnumWindowCallBack, (LPARAM)&procwin);
if (NULL == procwin.hWnd)
{
Sleep(200);
EnumWindows(EnumWindowCallBack, (LPARAM)&procwin);
}
return procwin.hWnd;
}
return NULL;
}
主要通过EnumWindows来枚举所有窗口,并通过GetWindowThreadProcessId来获取窗口的进程ID,并与1中打开的进程ID作比较来获取对应窗口的句柄。
// 查找进程主窗口的回调函数
BOOL CALLBACK EnumWindowCallBack(HWND hWnd, LPARAM lParam)
{
PROCESS_INFO *pProcessWindow = (PROCESS_INFO *)lParam;
DWORD dwProcessId;
GetWindowThreadProcessId(hWnd, &dwProcessId);
if (pProcessWindow->dwProcessId == dwProcessId && IsWindowEnabled(hWnd) && GetParent(hWnd) == NULL)
{
pProcessWindow->hWnd = hWnd;
return FALSE;
}
return TRUE;
}
为了让thirdUI内嵌入MainUI中,需要以下设置:
当窗口最小化或者切换到主进程的其他页面后,再切换回来,此时也需要刷新设置。否则会更新错误。重点,必须再次设置SetParent,否则无法正确传递消息。(具体原因未知)