[MFC] 基于多进程的窗口程序设计 & 窗口分离与合并(仿chrome的窗口分离效果)

时间:2021-02-20 16:42:08

什么是基于多进程的窗口程序设计?
基于这种设计的程序:表面上主窗口只有一个进程 实际上是多个进程
举个例子 当使用chrome浏览器打开多个tab页面时  如下图所示:

[MFC] 基于多进程的窗口程序设计 & 窗口分离与合并(仿chrome的窗口分离效果)

表面上看 是一个chrome窗口中包含了多个tab项  实际上是一个chrome外壳进程 内嵌了多个子进程  
子进程以子窗口的形式内嵌在chrome外壳中  一个tab项就是一个子进程 。此时打开任务管理器会发现 有很多个chrome的进程 如下图所示

[MFC] 基于多进程的窗口程序设计 & 窗口分离与合并(仿chrome的窗口分离效果)

如果用鼠标按住一个tab项 并将其从chrome浏览器中拖出来 这个tab项又会处于一个新的chrome浏览器中 :

[MFC] 基于多进程的窗口程序设计 & 窗口分离与合并(仿chrome的窗口分离效果)

这种设计的优点
个人觉得 这种设计最大的好处就是稳定:每一个tab项均采用一个独立的进程 核心的业务逻辑分布在多个子进程中实现  所有的子进程 用一个外壳包裹 。测试demo发现 如果某个子进程崩溃 并不会影响外壳进程和其他子进程 即模块1的不稳定 并不会影响模块2 因为各模块都实现在一个独立的进程中  实际开发中 可以在外壳进程中写一个监控模块 当发现某个子进程异常时 重启该进程 就能在界面上给用户一种“程序永不崩溃”的假象
这种设计的缺点 
模块间的通信 转变成了进程间的通信 会增加一定量的开发工作

窗口分离与合并
除了上面提到的chrome浏览器中的tab的效果以外 还有很多软件有这种效果:
界面中的某个窗口既可以与主窗口合并 也可以脱离主窗口单独作为一个顶层窗口  

如何实现这种功能?
本文给出两个关键函数:分离函数、合并函数 
// 函数功能:分离子进程
// hChildWindow : 子进程的主窗口句柄
void ReleaseChildProcess(HWND hChildWindow)
{
::SetParent(hChildWindow, 0);
::ModifyStyle(hChildWindow, WS_CHILD, WS_POPUP | WS_BORDER | WS_DLGFRAME, NULL);
::MoveWindow(hChildWindow, 0, 0, 200, 200); // 将子进程移动到桌面的左上角
}

// 函数功能:合并子进程
// hShellWindow : 外壳进程的主窗口句柄
// hChildWindow : 子进程的主窗口句柄
void CombineChildProcess(HWND hShellWindow, HWND hChildWindow)
{
::ModifyStyle(hChildWindow, WS_POPUP | WS_BORDER | WS_DLGFRAME, WS_CHILD, NULL);
::SetParent(hChildWindow, hShellWindow);
::MoveWindow(hChildWindow, 0, 0, 200, 200); // 将子进程移动到外壳进程的左上角
}
看完上面的代码后 可能会有人问:如何在外壳进程中拿到子进程的窗口句柄hChildWIndow?   
方法很多 虽然很简单 但也提一下吧:
方法1:通过子进程窗口的ClassName或TitleName 外壳进程中利用API函数FindWindow(...) 找到子进程的句柄
方法2:外壳进程启动子进程时 通过命令行的方式传递外壳进程的窗口句柄  子进程中通过PostMessage()向外壳进程回传自己的句柄
方法3:基于任意一种进程通信的方法 (此处略过不表 个人觉得前面两种方法简单一些)