具体做法,上面给出的链接里有大概说明,另外在cef_message_router.h中有详细说明,它分了9步,有需要的可以去查看。我试验了下可行。按照我的实验,从三个方面来说说:
browser进程
renderer进程
html中的js
foruok原创,转载请关注微信订阅号“程序视界”联系foruok。
browser进程
1)配置browser进程这一侧的Message Router
使用CefMessageRouterConfig来定义可以在html中使用的方法名字。代码片段可能如下:
...
CefMessageRouterConfig g_messageRouterConfig
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTRlpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance)
UNREFERENCED_PARAMETER(lpCmdLine)
// Enable High-DPI support on Windows 7 or newer.
CefEnableHighDPISupport()
g_messageRouterConfig.js_query_function = "cefQuery"
g_messageRouterConfig.js_cancel_function = "cefQueryCancel"
CefMainArgs main_args(hInstance)
...
}
注意我在main函数之外定义了一个CefMessageRouterConfig的实例,然后在main函数中设置了query和cancel这两个函数。它们定义了可以在html的js代码里使用的方法,比如根据上面代码,你可以用window.cefQuery({…})。
2)创建CefMessageRouterBrowserSide的实例
browser进程这边需要一个CefMessageRouterBrowserSide的实例来处理renderer进程发过来的消息。建议把这个实例作为成员变量放在CefClient的派生类中,因为它CefMessageRouterBrowserSide定义了一些方法,需要在指定的地方调用。
声明和初始化的代码片段:
CefRefPtr<CefMessageRouterBrowserSide>m_browser_side_router
...
extern CefMessageRouterConfig g_messageRouterConfig
m_browser_side_router = CefMessageRouterBrowserSide::Create(g_messageRouterConfig)
...
3)调用预定义方法
CefMessageRouterBrowserSide预定义了下列接口,需要在指定地方调用:
// call from CefClient::OnProcessMessageReceived
bool OnProcessMessageReceived(...)
// call from CefLifeSpanHandler::OnBeforeClose()
void OnBeforeClose(CefRefPtr<CefBrowser>browser)
// call from CefRequestHandler::OnRenderProcessTerminated()
void OnRenderProcessTerminated(CefRefPtr<CefBrowser>browser)
// call from CefRequestHandler::OnBeforeBrowse()
void OnBeforeBrowse(...)
所以,我们的这个ClientHandler类,声明如下:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
}
ClientHandler要实现CefClient的OnProcessMessageReceived、CefLifeSpanHandler的OnBeforeClose、CefRequestHandler的OnRenderProcessTerminated和OnBeforeBrowse方法,在这些方法里调用CefMessageRouterBrowserSide的同名方法即可。代码片段如下:
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser>browser)
{
CEF_REQUIRE_UI_THREAD()
m_browser_side_router->OnBeforeClose(browser)
...
}
bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser>browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage>message)
{
if (m_browser_side_router->OnProcessMessageReceived(browser, source_process, message)) return true
return false
}
bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser>browser, CefRefPtr<CefFrame>frame, CefRefPtr<CefRequest>request, bool is_redirect)
{
m_browser_side_router->OnBeforeBrowse(browser, frame)
return false
}
void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser>browser, TerminationStatus status)
{
m_browser_side_router->OnRenderProcessTerminated(browser)
}
4) 在browser进程里实现处理JS查询的handler
CefMessageRouterBrowserSide定义了一个内部类Handler,继承它:
class BrowserSideJSHandler : public CefMessageRouterBrowserSide::Handler
{
public:
BrowserSideJSHandler()
virtual bool OnQuery(CefRefPtr<CefBrowser>browser,
CefRefPtr<CefFrame>frame,
int64 query_id,
const CefString&request,
bool persistent,
CefRefPtr<Callback>callback)
virtual void OnQueryCanceled(CefRefPtr<CefBrowser>browser,
CefRefPtr<CefFrame>frame,
int64 query_id)
}
实现 OnQuery 和 OnQueryCanceled两个方法:
bool BrowserSideJSHandlerwww.SCJGCJ.COM?OnQuery(CefRefPtr<CefBrowser>browser,
CefRefPtr<CefFrame>frame, int64 query_id,
const CefString&request, bool persistent, CefRefPtr<Callback>callback)
{
if (request == "HelloCefQuery")
{
callback->Success("HelloCefQuery Ok")
return true
}
else if (request == "GiveMeMoney")
{
callback->Failure(404, "There are none thus query!")
return true
}
return false// give other handler chance
}
void BrowserSideJSHandler::OnQueryCanceled(CefRefPtr<CefBrowser>browser, CefRefPtr<CefFrame>frame, int64 query_id)
{
//cancel our async query task...
}
5)给CefMessageRouterBrowserSide的实例添加handler
我在ClientHandler类中定义了一个BrowserSideJSHandler的实例,类似下面:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
CefRefPtr<CefMessageRouterBrowserSide>m_browser_side_router
BrowserSideJSHandler m_jsHandler
...
}
然后在ClientHandler构造函数中加入了下列代码:
m_browser_side_router->AddHandler(&m_jsHandler, true)
上面的代码把BrowserSideJSHandler加入到browser进程里的消息路由器中。
好了,到这里browser进程配置完成。接下来看renderer进程。
1.打开一个新窗口:window.open()为了便于父窗口操作子窗口可以为window.open()定义一个变量,例如:var opW = window.open(‘tests.html’,’popup’,’width=300,height=300′)
这样要关闭子窗口可直接使用:opW.close()
要操作子窗口元素,例如:
opW.document.getElementById(“fartherWindowTxt”).innerHTML = “操作子窗口”
2.子窗口可以使用window.opener来引用父窗口:window.opener.document.getElementById(“fartherWindowTxt”).innerHTML=”子窗口操作父窗口!”
3.窗口关闭自身窗口可以使用:window.close()
点击查看demo:http://www.css88.com/demo/window-tongxin/