CEF融入MFC

前面我们分析了CefSample的代码,那么现在我们将基于MFC的Dialog做一个简单的CefDemo模型。
CefSample使用的是Cef自己的消息环CefRunMessageLoop。但是在使用MFC的时候,MFC有自己的消息环,所以我们不能再使用CefRunMessageLoop,所以我们需要在MFC的消息环里面处理Cef的消息,代码如下,重写虚函数PumpMessage:

BOOL CCefDemoApp::PumpMessage()
{
	auto result = CWinApp::PumpMessage();

	//Cef Message 
	CefDoMessageLoopWork();
	
	return result;

}

因为我们需要创建CEF子窗口,所以我们把CefInitialize放在Dialong::OnInitDialog里面初始化,并且绑定父窗口的句柄,然后在CefApp::OnContextInitialized里面创建浏览器(CefExecuteProcess还是放在入口函数执行即:InitInstance),代码如下:

BOOL CCefDemoDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	...
	// TODO:  在此添加额外的初始化代码
	if (m_browser_app == nullptr)
	{
		m_browser_app = new CBrowserApp(GetSafeHwnd());
		m_browser_app->Init(AfxGetInstanceHandle());
	}
		
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

///初始化CEFAPP
bool CBrowserApp::Init(HINSTANCE hist)
{
	CefEnableHighDPISupport();
	CefMainArgs cef_main_args(hist);
	CefSettings cef_settings;
	cef_settings.multi_threaded_message_loop = true;
	cef_settings.no_sandbox = true;

	return CefInitialize(cef_main_args, cef_settings, this, NULL);
}

void CBrowserApp::OnContextInitialized()
{
	CEF_REQUIRE_UI_THREAD();
	RECT rtClient;
	::GetClientRect(m_hWndParent, &rtClient);

	CefWindowInfo wnd_info;
	wnd_info.SetAsChild(m_hWndParent, rtClient);

	CefBrowserSettings browser_settings;
	CefBrowserHost::CreateBrowser(wnd_info, m_simple_handler, "http://www.baidu.com", browser_settings, NULL);
}

然后就是最重要的一关就是在关闭对话框的时候必须先关闭Cef所有打开的浏览器才行否则会崩溃或者进程驻留,所以我们需要在Dialog的时候关闭所有的浏览器(调用了CloseBrowser后,CEF会调用DoClose,然后会再发一个WM_CLOSE给窗口),并且在App退出之前调用CefShutdown(),代码如下:

//关闭对话框之前,关闭所有的Cef浏览器
void CCefDemoDlg::OnClose()
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	//尝试关闭浏览器,如果成功则直接返回,拦截当次WM_CLOSE消息,等待CEF关闭完成之后发送的WM_CLOSE的消息
	if (m_browser_app && m_browser_app.get() && m_browser_app->TryClose())
		return;

	CDialogEx::OnClose();
}

//App里面尝试关闭所有的浏览器,如果浏览器已经全部关闭则返回false,否则返回true
bool CBrowserApp::TryClose()
{
	if (m_simple_handler && m_simple_handler.get() &&
		!m_simple_handler->IsClosing())
	{
		m_simple_handler->CloseAllBrowsers(true);
		return true;
	}
	return false;
}

//这里是完全仿照CefSanple实现的,
void CBrowserHandler::CloseAllBrowsers(bool force_close)
{
	if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		// bind ref cef_closure_task
		CefPostTask(TID_UI, base::Bind(&CBrowserHandler::CloseAllBrowsers, this,force_close));
		return;
	}

	if (m_browser_list.empty())
		return;

	std::list<CefRefPtr<CefBrowser> >::const_iterator it = m_browser_list.begin();
	for (; it != m_browser_list.end(); ++it)
		(*it)->GetHost()->CloseBrowser(force_close);
}

//退出应用程序之前记得释放Cef资源,否则崩溃
int CCefDemoApp::ExitInstance()
{
	// TODO:  在此添加专用代码和/或调用基类
	CefShutdown();
	return CWinApp::ExitInstance();
}

此时基于MFC的CefDemo运行成功,效果如下,但是我们打开其他网页的时候可能弹出了一个新的POP窗口,那么我们怎么实现像浏览器一样的标签页弹出呢?下一章将描述怎么实现一个简单的多标签的Cef浏览器。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/CAir2/article/details/85050847
CEF
MFC