顺着我之前写的文章,关于MFC嵌入并使用CEF之后,实现了多选项卡、C++与JS通信等功能之后,CEF在C++里面的使用基本是差不多了,剩下的就是了解browser接口、Frame接口、Context接口以及BrowserProcessHandler和RenderProcessHandler接口,只要我们将所有接口方法理清楚弄明白,相信CEF在C++中的使用就可以告一段落了,顺着这个思路我观察到cefClient接口中有一个接口OnProcessMessageReceived和RenderProcessHandler中也有一个OnProcessMessageReceived接口,看注释就知道,这是处理不同进程发送过来的消息,我们知道CEF是由多进程方式实现的(默认情况,按照我前一篇文章可以改成单进程方式),不同进程之间通信就是通过浏览器CefBrowser的消息发送接口SendProcessMessage实现的,所以我们这章讲的就是有关如何在Browser进程与Renderer进程之间进行通信(当然所有的接口中还有有关上下文菜单、复制、拷贝等接口,但是我觉得进程通信这块更重要)。
还是按照以往方式,首先摆出问题:
(1)Renderer进程如何发送消息给Browser进程
(2)Browser进程如何发送消息给Renderer进程
围绕以上问题,在我原有的代码(http://download.csdn.net/detail/lixiang987654321/9602430)上回答以上两个问题,以下我们做一个简单的功能Render给Browser发一个消息,然后Browser验证后回复一个消息(cef中PID_BROWSER代表Browser浏览器进程,PID_RENDER代表Render进程):
(1)Renderer发送消息给Browser
通过我前一篇文章知道js引擎是运行在Renderer进程中的,在cefv8handler中js的处理函数中我们将函数名发送给browser进程,让其验证改函数,然后回复验证结果给Renderer进程,那么在Renderer中我们发送一个消息给Browser:
[cpp] view plain copy
- bool CV8JsHandler::Execute(const CefString& func_name,
- CefRefPtr<CefV8Value> object,
- const CefV8ValueList& arguments,
- CefRefPtr<CefV8Value>& retval,
- CefString& exception)
- {
- // send message to browser process that method began to execute
- <span style="color:#ff0000;"> CefRefPtr<CefProcessMessage> objMsg = CefProcessMessage::Create(_T("msg_from_render"));
- CefRefPtr<CefListValue> arglist = objMsg->GetArgumentList();
- arglist->SetString(0, /*CefV8Value::CreateString()*/func_name);
- CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, objMsg);</span>
- if (func_name == _T("addFunction"))
- {
- int32 nSum = 0;
- for (size_t i = 0; i < arguments.size(); ++i)
- {
- if(!arguments[i]->IsInt())
- return false;
- nSum += arguments[i]->GetIntValue();
- }
- retval = CefV8Value::CreateInt(nSum);
- return true;
- }
- else if (func_name == _T("hehe"))
- {
- retval = CefV8Value::CreateString(_T("hehe hehe!"));
- return true;
- }
- else
- {
- return false;
- }
- }
(2)Browser回复对应消息
每一个Browser都有一个CefClient,cefclient实现所有消息或事件处理接口处理浏览器的所有事件,所以cefclient是运行在browser中的事件处理器,我们在Cefclient的实现中实现OnProcessMessageReceived接口,处理来自其他进程的消息:
[cpp] view plain copy
- bool CCefBrowserEventHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
- CefProcessId source_process,
- CefRefPtr<CefProcessMessage> message) OVERRIDE
- {
- if (message->GetName() == _T("msg_from_render"))
- {
- CefRefPtr<CefListValue> argList = message->GetArgumentList();
- CefString strFunctionName = argList->GetString(0);
- bool bAllow = false;
- if (strFunctionName == _T("addFunction"))
- {
- bAllow = true;
- }
- CefRefPtr<CefProcessMessage> msg_back = CefProcessMessage::Create(_T("func_back"));
- msg_back->GetArgumentList()->SetString(0, strFunctionName);
- msg_back->GetArgumentList()->SetBool(1, bAllow);
- browser->SendProcessMessage(PID_RENDERER, msg_back);
- return true;
- }
- return false; // has handle for the message
- }
我做的简单操作就是,当直接addFunction函数的时候验证有效,否则无效!返回将结果回复给PID_RENDER进程。
(3)Renderer处理回复
在Render进程处理器中处理OnProcessMessageReceived接口,检查回复:
[cpp] view plain copy
- bool CCefBrowserApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
- CefProcessId source_process,
- CefRefPtr<CefProcessMessage> message)
- {
- if (message->GetName() == _T("func_back"))
- {
- // extract message
- CefRefPtr<CefListValue> args = message->GetArgumentList();
- CefString strFunctionName = args->GetString(0);
- bool bAllow = args->GetBool(1);
- CString strMsg;
- strMsg.Format(_T("alert('function %s status %d')"), strFunctionName.c_str(), bAllow);
- browser->GetMainFrame()->ExecuteJavaScript((LPCTSTR)strMsg, browser->GetMainFrame()->GetURL(), 0);
- return true;
- }
- return false;
- }
通过以上一个消息循环,大家知道cef中Render进程和browser进程通信其实很简单,就是通过浏览器Browser的SendProcessMessage方法实现的,这里的这个方法就类似于MFC的Postmessage方法,它是异步的,不是同步的方法。
关于CEF中进程通信很简单,我就说道这里,截图如下:
browser中收到render消息:
browser回复消息到render中,render收到结果:
browser中收到render消息:
browser回复消息到render中,render收到结果:
实例代码:http://download.csdn.net/detail/lixiang987654321/9602615