CEF CloseBrowser

此处针对的是一个CefClient管理多个CefBrowser的情景。
情景实现步骤:进入百度首页=》新闻=》随便点击一个新闻(此时会创建一个新CefBrowser,cef默认是popup,我们修改为WS_CHILD,实现多标签页,具体实现下一章介绍)

cefsample的实例中我们知道了cefclient的生命周期需要自己管理,并且在退出的时候调用CefBrowserHost::CloseBrowser(false)或者CefBrowserHost::TryCloseBrowser(),随后触发DoClose(注意:DoClose调用之后OnBeforeClose并不是一定被调用,这个和CefClient的生命周期有关

在Cef多标签浏览器的时候我们实现了CloseAllBrowsers,OnAfterCreated,OnBeforeClose实现CefClient生命周期管理。代码如下(有问题代码):

void CBrowserHandler::CloseAllBrowsers()
{
		if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		// bind ref cef_closure_task
		CefPostTask(TID_UI, base::Bind(&CBrowserHandler::CloseAllBrowsers, this));
		return;
	}

	if (m_browser_list.empty())
		return;
		
	std::vector<CefRefPtr<CefBrowser> >::const_iterator it = m_browser_list.begin();
	for (it; it != m_browser_list.end(); ++it)
		(*it)->GetHost()->TryCloseBrowser();// CloseBrowser(force_close);
			
}

bool CBrowserHandler::DoClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();
	m_is_closing = (m_browser_list.size() <= 0);

	return false;
}

void CBrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();

	// Remove from the list of existing browsers.
	std::vector<CefRefPtr<CefBrowser> >::iterator bit = m_browser_list.begin();
	for (; bit != m_browser_list.end(); ++bit) {
		if ((*bit)->IsSame(browser)) {
			m_browser_list.erase(bit);
			break;
		}
	}
}

测试结果:多标签的时候程序关闭不了,原因:m_is_closing 始终为false。N个标签的时候虽然系统调用了N次DoClose,但是OnBeforeClose却一次也没有调用,所以m_is_closing 的条件始终不会成立。

修改代码,把删除操作放在DoClose里面管理,代码如下:

void CBrowserHandler::CloseAllBrowsers()
{
		if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		// bind ref cef_closure_task
		CefPostTask(TID_UI, base::Bind(&CBrowserHandler::CloseAllBrowsers, this));
		return;
	}

	if (m_browser_list.empty())
		return;
		
	std::vector<CefRefPtr<CefBrowser> >::const_iterator it = m_browser_list.begin();
	for (it; it != m_browser_list.end(); ++it)
		(*it)->GetHost()->TryCloseBrowser();// CloseBrowser(force_close);
			
}

bool CBrowserHandler::DoClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();

	std::vector<CefRefPtr<CefBrowser> >::iterator bit = m_browser_list.begin();
	for (; bit != m_browser_list.end(); ++bit) {
		if ((*bit)->IsSame(browser)) {
			m_browser_list.erase(bit);
			break;
		}
	}

	m_is_closing = (m_browser_list.size() <= 0);

	return false;
}

void CBrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();
}

运行结果:在这里插入图片描述
为什么会迭代器无效呢?调试发现

for (it; it != m_browser_list.end();++it)
		(*it)->GetHost()->TryCloseBrowser();// CloseBrowser(force_close);

for关闭浏览器的的时候会触发DoClose,此时DoClose里面删除了元素导致迭代器失效。此时当再次操作迭代器it的时候就会触发异常了。所以修改CloseAllBrowsers代码如下:

void CBrowserHandler::CloseAllBrowsers()
{
	if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		// bind ref cef_closure_task
		CefPostTask(TID_UI, base::Bind(&CBrowserHandler::CloseAllBrowsers, this));
		return;
	}

	if (m_browser_list.empty())
		return;
		
	//建立一个副本操作
	std::vector<CefRefPtr<CefBrowser> > temp_browser_list = m_browser_list;
	std::vector<CefRefPtr<CefBrowser> >::const_iterator it = temp_browser_list.begin();
	for (it; it != temp_browser_list.end(); ++it)
		(*it)->GetHost()->TryCloseBrowser();// CloseBrowser(force_close);
}

运行结果和预期一致。但是调试的过程发现一个新问题?理论上调用一次CloseAllBrowsers就应该关闭所有的CefClient,即:for N次TryCloseBrowser触发N次DoClose。但是结果只调用了一次,而且是触发的最后一个调用对象的DoClose(DoClose会再次触发WM_CLOSE)(对象只有第一次调用TryCloseBrowser才会触发DoClose,后面再次调用都不会再触发DoClose)。(由于cef源码没有编译,所以这里暂时不知道为什么会这样,如果知道的大神请告诉一下)。

作者:cqclark
来源:CSDN
原文:https://blog.csdn.net/cqclark/article/details/49121027
版权声明:本文为博主原创文章,转载请附上博文链接!
如果浏览器是其他窗口的父窗口,那么这个关闭事件会引起父窗口的系统函数调用。那父窗口需要调用 CloseBrowser(false) 并等待第二个系统调用的关闭事件来指示浏览进程允许关闭。
如果关闭通过Javascript事件或DoClose()回调函数处理,那第二个系统关闭事件就不会被发送。
IsClosing()测试是否关闭,如果是第一次的系统关闭事件就返回false,每二次返回true;


所以最终修改代码如下:

void CBrowserHandler::CloseAllBrowsers()
{
	if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		// bind ref cef_closure_task
		CefPostTask(TID_UI, base::Bind(&CBrowserHandler::CloseAllBrowsers, this));
		return;
	}

	if (m_browser_list.empty())
		return;

	//一次只能关闭一个CefBrowser=》DoClose,即使关闭多个也只会调用一次DoClose
 	std::vector<CefRefPtr<CefBrowser> >::const_iterator it = m_browser_list.begin();
 	if (it != m_browser_list.end())
 		(*it)->GetHost()->TryCloseBrowser();// CloseBrowser(force_close);

}

bool CBrowserHandler::DoClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();

	std::vector<CefRefPtr<CefBrowser> >::iterator bit = m_browser_list.begin();
	for (; bit != m_browser_list.end(); ++bit) {
		if ((*bit)->IsSame(browser)) {
			m_browser_list.erase(bit);
			break;
		}
	}

	m_is_closing = (m_browser_list.size() <= 0);

	return false;
}

void CBrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 
{
	CEF_REQUIRE_UI_THREAD();
}

此时多标签浏览器可以正常关闭并且没有进程驻留

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/CAir2/article/details/85130714
CEF
今日推荐