什么是基于多进程的窗口程序设计?
基于这种设计的程序:表面上主窗口只有一个进程 实际上是多个进程
举个例子 当使用chrome浏览器打开多个tab页面时 如下图所示:
子进程以子窗口的形式内嵌在chrome外壳中 一个tab项就是一个子进程 。此时打开任务管理器会发现 有很多个chrome的进程 如下图所示
如果用鼠标按住一个tab项 并将其从chrome浏览器中拖出来 这个tab项又会处于一个新的chrome浏览器中 :
个人觉得 这种设计最大的好处就是稳定:每一个tab项均采用一个独立的进程 核心的业务逻辑分布在多个子进程中实现 所有的子进程 用一个外壳包裹 。测试demo发现 如果某个子进程崩溃 并不会影响外壳进程和其他子进程 即模块1的不稳定 并不会影响模块2 因为各模块都实现在一个独立的进程中 实际开发中 可以在外壳进程中写一个监控模块 当发现某个子进程异常时 重启该进程 就能在界面上给用户一种“程序永不崩溃”的假象
这种设计的缺点
模块间的通信 转变成了进程间的通信 会增加一定量的开发工作
窗口分离与合并
除了上面提到的chrome浏览器中的tab的效果以外 还有很多软件有这种效果:
界面中的某个窗口既可以与主窗口合并 也可以脱离主窗口单独作为一个顶层窗口 如何实现这种功能?
本文给出两个关键函数:分离函数、合并函数
// 函数功能:分离子进程看完上面的代码后 可能会有人问:如何在外壳进程中拿到子进程的窗口句柄hChildWIndow?
// 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); // 将子进程移动到外壳进程的左上角
}
方法很多 虽然很简单 但也提一下吧:
方法1:通过子进程窗口的ClassName或TitleName 外壳进程中利用API函数FindWindow(...) 找到子进程的句柄
方法2:外壳进程启动子进程时 通过命令行的方式传递外壳进程的窗口句柄 子进程中通过PostMessage()向外壳进程回传自己的句柄
方法3:基于任意一种进程通信的方法 (此处略过不表 个人觉得前面两种方法简单一些)