Cef的JavaScript和MFC通信

在我另一篇文章裏面介紹瞭如何在JavaScript中調用MFC的代碼和MFC中調用JavaScript的代碼,但是文中提到一個問題:
在vs代碼CSimpleV8Handler::Execute中打斷點始終停不下來,一直以爲是電腦問題,糾結了很久,最後發現是因爲我加載cef的時候用的是多進程模式,代碼設置如下:

	void* sandbox_info = NULL;
	CefMainArgs main_args(AfxGetApp()->m_hInstance);
	CefRefPtr<SimpleApp> app(new SimpleApp);
	CefSettings settings;
	settings.no_sandbox = true;
	//settings.single_process = true;
	settings.multi_threaded_message_loop = true;
	CefInitialize(main_args, settings, app.get(), sandbox_info);

如果放開那句註釋,斷點是可以停下來的,到此才發現問題所在,因爲v8的消息在另一個進程中(Render進程),根本不在當前cef瀏覽器進程中,所以斷點是不會起作用的,如果只是使用單進程模式,就沒啥問題。
如果一定要用多進程模式,這裏打不了斷點,而且這裏也訪問不了當前窗口的任何句柄(我就是因爲需要調用窗口中其他控件,獲取到的空間指針和主窗口指針都是空),查了一下,要在代碼中真正的訪問mfc窗口的句柄,需要將Render進程中的消息傳遞到Browser進程中,在Browser進程中去訪問纔可以,下面介紹如何將消息回傳到Browser進程中:
發送消息使用CefBrowser::SendProcessMessage(),SendProcessMessage第一個參數是CefProcessId,給Browser進程發送,就用PID_BROWSER,給Render進程發送,就用PID_RENDERER。所以在v8代碼中,寫成下面這樣:

if (arguments.size() ==1 ){			
	CefString str = arguments[0]->GetStringValue();
	CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("JSCallCppMsg");
	CefRefPtr<CefListValue> args = msg->GetArgumentList();
	args->SetSize(1);
	args->SetString(0, str);
	CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg);
	return true;
}

其中字符串JSCallCppMsg是隨便定義的,是用來在Browser進程中用來區分消息用的。在Browser進程中需要重寫一個方法:OnProcessMessageReceived,整個方法的定義是在CefClient類中,cef_client.h中定義如下:

virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefProcessId source_process,CefRefPtr<CefProcessMessage> message) {
	return false;
}

在SimpleHandler中重寫這個方法,代碼如下:

bool SimpleHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) {
	const std::string& messageName = message->GetName();
	if (messageName == "JSCallCppMsg"){
		CefRefPtr<CefListValue> args = message->GetArgumentList();
		CefString str = args->GetString(0);
		::SendMessage(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), WM_TESTSENDMSG, 0, (LPARAM)str.c_str());
		return true;
	}
	return false;
}

其中SendMessage是用來向MFC主窗口發送消息的,因爲那些控件需要在主窗口中才能拿到,所以將消息傳遞到主窗口中,至於爲什麼不用PostMessage,原因是PostMessage發送消息後不等待消息處理,這裏的字符串是臨時變量,本段代碼執行完成後就銷燬了,MFC消息循環中拿到的字符串就是亂碼。

本文中用到的代碼可以在https://download.csdn.net/download/youyicc/12113708地址上下載,這是一個基於VS2013的mfc上顯示cef瀏覽器和ie插件瀏覽器,實現cef的JavaScript和ie的JavaScript相互調用的示例代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章