NO IMAGE

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage提到了CEF提供的Browser與Browser程序通訊的幾種機制,我實驗了Process Runtime Messages這種方式,用到了CefProcessMessage和CefBrowser::SendProcessMessage()。

我是在CEF中JS與C 互動一文的基礎上完成的,我們邊說基本步驟,邊給出關鍵程式碼。

foruok原創,如需轉載請關注foruok的微信訂閱號“程式視界”聯絡foruok。

    1. 傳送訊息

傳送訊息使用CefBrowser::SendProcessMessage() ,SendProcessMessage第一個引數是CefProcessId,給Browser程序傳送,就用PID_BROWSER,給Render程序傳送,就用PID_RENDERER。

我在Render程序傳送訊息的程式碼如下(ClientV8Handler的Execute方法內):

        CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("login_msg");
// Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg->GetArgumentList();
// Populate the argument values.
args->SetSize(2);
args->SetString(0, strUser);
args->SetString(1, strPassword);
// Send the process message to the browser process.
CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg);

我把那個cef_js_integration示例中收到的登陸訊息(Render程序)傳送給Browser程序。

    1. 處理訊息

Browser程序這邊,重寫CefClient::OnProcessMessageReceived()這個方法來處理跨程序訊息。

以cef_js_integration為例,是在ClientHandler中重寫了OnProcessMessageReceived方法:

bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
const std::string& messageName = message->GetName();
if (messageName == "login_msg") 
{   
// extract message
CefRefPtr<CefListValue> args = message->GetArgumentList();
CefString strUser = args->GetString(0);
CefString strPassword = args->GetString(1);
TCHAR szLog[256] = { 0 };
_stprintf_s(szLog, 256, _T("BrowserProcess, user - %s, password - %s\r\n"), strUser.c_str(), strPassword.c_str());
OutputDebugString(szLog);
//send reply to render process
CefRefPtr<CefProcessMessage> outMsg = CefProcessMessage::Create("login_reply");
// Retrieve the argument list object.
CefRefPtr<CefListValue> replyArgs = outMsg->GetArgumentList();
// Populate the argument values.
replyArgs->SetSize(1);
replyArgs->SetInt(0, 0);
// Send the process message to the renderer process.
browser->SendProcessMessage(PID_RENDERER, outMsg);
return true;
}
return false;
}

可以看到,上面的程式碼又給Render程序發了個訊息。

Render程序這邊, 重寫CefRenderProcessHandler::OnProcessMessageReceived()方法來處理來自Browser程序的訊息,具體程式碼在ClientAppRender類中:

bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
const std::string& messageName = message->GetName();
if (messageName == "login_reply")
{
// extract message
CefRefPtr<CefListValue> args = message->GetArgumentList();
int status = args->GetInt(0);
OutputDebugString(status == 0 ? _T("Renderer process, login ok\r\n") : _T("Renderer process, login failed\r\n"));
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
frame->ExecuteJavaScript("alert('Got Login Reply from Browser process')", frame->GetURL(), 0);
return true;
}
return false;
}

好啦,這就是整個過程了。

其他參考文章: