绘控件在CefControl控件的Paint方法里,把dc_cef_popup_的位图数据按照rect_popup_的信息拷贝到duilib传入的HDC中当弹出框消失时,触发
CefRenderHandler::OnPopupShow接口,这里重置rect_popup_的信息,并且通知CefBrowser刷新页面
多进程渲染
Cef3支持多进程和单进程渲染,但是单进程渲染不够稳定,只应该在Debug模式下作为调试目的使用。在Cef3.1916等好几个版本中,调试状态下使用单进程模式,当程序初始化或者退出时,会触发中断。但是在多进程模式下没有问题。官方也明确说明不推荐使用单进程模式
CefManager类实现了Cef3的初始化和销毁功能。初始化函数Initialize里调用的CefExecuteProcess函数会检测当前的进程类型,如果是浏览器进程则函数会直接返回,在其他进程的话这个函数会阻塞直接进程销毁。
ClientApp类继承CefBrowserProcessHandler和
CefRenderProcessHandler,可以同时处理浏览器进程和渲染进程的消息。原本多进程模式中,浏览器进程和渲染进程
可以同用一个程序。但是由于我们的主程序的代码比较复杂,如果让主程序多开进程的话,会占用较多的内存和CPU,同时触发不必要的问题。所以专门另写了一个cef_render项目来作为渲染子进程
cef_render项目代码比较简单,主要代码都是继承CefRenderProcessHandler接口的
CefRenderProcessHandler类。考虑到代码周全,以后可以在cef_render项目补充一些崩溃Dump处理等代码。务必要保证主程序的CefRenderProcessHandler接口实现代码与cef_render程序的CefRenderProcessHandler接口实现代一致。否则单进程和多进程模式下会出现不同的处理结果
在浏览器进程启动时,通过附加参数可以指定渲染子进程的路径
command_line->AppendSwitchWithValue(\process-path\
C++与JS交互
C++调用JS
在browser进程和render进程都可以直接执行JS代码,直接调用CefFrame对象的ExecuteJavaScript方法就可以
JS调用C++
网页中的一些JS回调和对网页的JS扩展,都必须在渲染进程操作。让JS调用C++的方法有三个,
http://www.cnblogs.com/guolixiucai/p/4943748.html里面介绍了两种,https://github.com/fanfeilong/cefutil里面是更复杂更强的第三种。
我们项目里,只需要给JS开放一个函数接口,而且接口并不复杂,所以直接采用JS扩展的方法注册JS回调函数就可以。
在CefRenderProcessHandler::OnWebKitInitialized接口里,注册JS扩展代码
std::string extensionCode = \
\ CefTestWebFunction = function(param) {\ \ native function CefTestWebFunction(param);\
\ return CefTestWebFunction(param);\ \ };\ \
CefRefPtr<CefV8Handler> handler = new CefJSHandler();
CefRegisterExtension(\handler);
CefRegisterExtension函数会执行扩展代码。网上例子都是创建一个全局对象,然后把JS函数和变量绑定到这个对象上。这里直接申明一个FunExternal的全局函数。当JS代码中调用FunExternal函数时,会根据native关键字后的函数名,去通知C++代码调用对应的native函数
CefJSHandler类继承CefV8Handler接口并实现Execute方法,在CefRegisterExtension传入CefJSHandle指针,当JS代码需要调用native函数时会,会主动触发CefJSHandler::Execute方法
bool CefJSHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const
CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) {
if (name == \arguments.size() == 1) {
for (auto &it : arguments) {
if (it->IsString()) {
CefString param = it->GetStringValue();
CefRefPtr<CefBrowser> browser = CefV8Context::GetCurrentContext()->GetBrowser(); CefRefPtr<CefProcessMessage> message =
CefProcessMessage::Create(kJsCallbackMessage);
message->GetArgumentList()->SetString(0, name);