CEF3 使用多进程。其中包括:一个浏览器进程、一个渲染进程和若干其他进程(处理插件的进程、处理GUP的进程等)。
- 浏览器进程处理窗口的创建和绘制,以及网络访问等,浏览器进程包含了应用程序的主要逻辑。
- 渲染进程负责渲染 HTML 以及执行 JavaScript ,访问 DOM 等。
- 其他进程则进行插件处理,GPU 处理等(如果有的话)。
- 多个进程之间通过 IPC (Inter-Process Communication) 通信。
默认情况下 CEF3 使用一个 exe 的多个实例来实现上述的多个进程。比如在 CEF3:用CEF3实现最简单的浏览器 中,在 WinMain 开始时会执行下面的代码:
// CEF applications have multiple sub-processes (render, plugin, GPU, etc)
// that share the same executable. This function checks the command-line and,
// if this is a sub-process, executes the appropriate logic.
int exit_code = CefExecuteProcess(main_args, NULL, NULL);
if (exit_code >= 0)
{
// The sub-process has completed so return here.
return exit_code;
}
这里 CefExecuteProcess() 会根据不同的命令行参数来执行不同的进程,如果是浏览器进程,该函数立即返回,返回值为 -1。如果是其他进程,则在浏览器退出时才返回,返回值是一个大于0的数。
运行结果如下图,可以看到同一个 exe 运行了三个实例。
也可以通过设置 CefSettings.browser_subprocess_path 来以不同的 exe 实现 CEF 的多个进程。下面通过示例说明这一点。
创建两个工程,一个命名为 BrowserProcess 作为浏览器进程,另一个命名为 BrowserSubProcess 作为其他子进程。工程的设置可以参见 CEF3:用CEF3实现最简单的浏览器。
在 BrowserProcess 工程下创建 main.cpp,编写如下代码。注意这里不再调用 CefExecuteProcess(),而是设置 CefSettings.browser_subprocess_path 的值来指定子进程路径。
#include "include/cef_app.h"
#include "include/cef_browser.h"
#include "include/cef_client.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include <Windows.h>
class MyClient : public CefClient, public CefLifeSpanHandler
{
public:
virtual ~MyClient() {}
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) override { CefQuitMessageLoop(); }
private:
IMPLEMENT_REFCOUNTING(MyClient);
};
class MyApp : public CefApp, public CefBrowserProcessHandler
{
public:
virtual ~MyApp() {}
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override { return this; }
virtual void OnContextInitialized() override
{
CEF_REQUIRE_UI_THREAD();
CefWindowInfo window_info;
window_info.SetAsPopup(NULL, "cefsimple");
CefRefPtr<MyClient> client(new MyClient());
CefString url = "http://www.baidu.com";
CefBrowserSettings browser_settings;
CefBrowserHost::CreateBrowser(window_info, client, url, browser_settings, NULL);
}
private:
IMPLEMENT_REFCOUNTING(MyApp);
};
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
CefMainArgs main_args(hInstance);
CefSettings settings;
settings.no_sandbox = true;
// 获取子进程路径
WCHAR subProcessPath[MAX_PATH] = { 0 };
GetModuleFileNameW(hInstance, subProcessPath, MAX_PATH);
*(wcsrchr(subProcessPath, L'\\') + 1) = L'\0';
LPCWSTR SUB_PROCESS_NAME = L"BrowserSubProcess.exe";
wcsncat_s(subProcessPath, MAX_PATH, SUB_PROCESS_NAME, wcslen(SUB_PROCESS_NAME));
// 设置子进程路径
cef_string_from_wide(subProcessPath, MAX_PATH, &settings.browser_subprocess_path);
auto myApp = CefRefPtr<MyApp>(new MyApp());
CefInitialize(main_args, settings, myApp.get(), NULL);
CefRunMessageLoop();
CefShutdown();
return 0;
}
在 BrowserSubProcess 工程下创建 main.cpp,编写如下代码。代码相当简单,仅仅是调用了 CefExecuteProcess()。
#include "include/cef_app.h"
#include <Windows.h>
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
CefMainArgs main_args(hInstance);
return CefExecuteProcess(main_args, NULL, NULL);
}
编译两个工程后,确保两个 exe 在同一目录下,运行,结果如下。可以看到运行了不同的 exe 。