duilib中 CEF 浏览器创建、结束流程

 

duilib中,专门设置了浏览器控件

一    CEF浏览器创建

XML加载过程中,会创建自定义的浏览器控件

ui::Control* CefNativeForm::CreateControl(const std::wstring& pstrClass)
{
	if (pstrClass == L"CefNativeControl")
	{
		return new CefNativeControl;
	}


	if (pstrClass == L"CefControl")
	{
		return new CefControl;
	}
	return NULL;
}

在此过程中,会对此控件基本信息赋值,Window::InitControls   比如控件所属窗口等

 

这个控件,首先是duilib控件,所以继承自control

同时,这个控件要处理一些浏览器事件,所以继承自 浏览器消息委托类 HandlerDelegate

 

class CefNativeControl :public Control, public nim_cef::BrowserHandler::HandlerDelegate
{
public:
	CefNativeControl(void);
	~CefNativeControl(void);	

	virtual void Init() override;
	virtual void SetPos(UiRect rc) override;
	virtual void HandleMessage(EventArgs& event) override;
	virtual void SetVisible(bool bVisible = true) override;
	virtual void SetInternVisible(bool bVisible = true) override;
	HWND GetCefHandle() const;

public:
	// 控件对外的控制接口
	void LoadURL(const CefString& url);
	void LoadString(const CefString& stringW, const CefString& url);
	void GoBack();
	void GoForward();
	bool CanGoBack();
	bool CanGoForward();
	void Refresh();
	void StopLoad();
	bool IsLoading();
	void ExecJavaScript(const CefString& js);

同时,有一个重要的变量  浏览器对象 CefRefPtr browser_handler_ = nullptr;,用此加载网页等

// BrowserHandler implements CefClient and a number of other interfaces.
class BrowserHandler : 
	public nbase::SupportWeakCallback,
	public CefClient,
	public CefLifeSpanHandler,
	public CefRenderHandler,
	public CefContextMenuHandler,
	public CefDisplayHandler,
	public CefDragHandler,
	public CefGeolocationHandler,
	public CefJSDialogHandler,
	public CefKeyboardHandler,	
	public CefLoadHandler,
	public CefRequestHandler,
	public CefDownloadHandler

初始化:

void CefNativeControl::Init()
{
	if (browser_handler_.get() == nullptr)
	{
		LONG style = GetWindowLong(m_pWindow->GetHWND(), GWL_STYLE);
		SetWindowLong(m_pWindow->GetHWND(), GWL_STYLE, style | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
		ASSERT((::GetWindowLong(m_pWindow->GetHWND(), GWL_EXSTYLE) & WS_EX_LAYERED) == 0 && L"无法在分层窗口内使用本控件");

		browser_handler_ = new nim_cef::BrowserHandler;
		browser_handler_->SetHostWindow(m_pWindow->GetHWND());  // 设置Cef浏览器对象所属的窗体的句柄
		browser_handler_->SetHandlerDelegate(this);             // 设置委托类指针,浏览器对象的一些事件会交给此指针对象来处理

		// 使用有窗模式
		CefWindowInfo window_info;  
		window_info.SetAsChild(this->m_pWindow->GetHWND(), m_rcItem);  // 设置浏览器在窗口中的区域  作为子窗口

		CefBrowserSettings browser_settings;
		CefBrowserHost::CreateBrowser(window_info, browser_handler_, L"", browser_settings, NULL);  //创建浏览器
	}

	__super::Init();
}

 

OnAfterCreated() 在浏览器对象被创建后立即调用,主应用程序通常用这个函数保存浏览器对象的引用

void BrowserHandler::OnAfterCreated(CefRefPtr browser)
{
	REQUIRE_UI_THREAD();	
	nbase::ThreadManager::PostTask(kThreadUI, ToWeakCallback([this, browser](){
		if (browser_client_ == nullptr)
			browser_client_ = browser->GetHost()->GetClient();
		browser_list_.emplace_back(browser);
		if (browser_ != nullptr)
			browser_->GetHost()->WasHidden(true);
		browser_ = browser;
		CefManager::GetInstance()->AddBrowserCount();//浏览器计数,方便销毁时判断是否销毁完毕
		// 有窗模式下,浏览器创建完毕后,让上层更新一下自己的位置;因为在异步状态下,上层更新位置时可能Cef窗口还没有创建出来
		if (!CefManager::GetInstance()->IsEnableOffsetRender())
		{
			handle_delegate_->UpdateWindowPos();
		}
		task_list_after_created_();
		task_list_after_created_.Clear();
	}));

}

 

二 CEF浏览器销毁

CefBrowserHost::CloseBrowser(false), 通知HOST开始关闭流程,参数force_close=false,我们是否强制关闭 (true 强制关闭,false交互式关闭)

CefBrowserHost::CloseBrowser(false)或者CefBrowserHost::TryCloseBrowser(),随后触发DoClose(注意:DoClose调用之后OnBeforeClose并不是一定被调用,这个和CefClient的生命周期有关

void BrowserHandler::OnBeforeClose(CefRefPtr browser)
{
	REQUIRE_UI_THREAD();
	nbase::ThreadManager::PostTask(kThreadUI, ToWeakCallback([this, browser](){
		CefManager::GetInstance()->SubBrowserCount();//浏览器计数 
		auto it = std::find_if(browser_list_.begin(), browser_list_.end(), [&](const CefRefPtr& item){
			return item->IsSame(browser);
		});
		if (it != browser_list_.end())
		{
			auto closed_browser = *it;
			browser_list_.erase(it);
			if (closed_browser->IsSame(browser_))
			{
				browser_ = browser_list_.size() > 0 ? *browser_list_.rbegin() : nullptr;
				if (browser_ != nullptr)
				{
					browser_->GetHost()->WasHidden(false);
				//	browser_->Reload();
				}
			}
		}
	}));	
}

 

三 duilib cef窗口销毁

含浏览器控件的窗口,销毁时,会将浏览器控件销毁


CefNativeControl::~CefNativeControl(void)
{
	ReleaseBroser();
}

void CefNativeControl::ReleaseBroser()
{
	if (browser_handler_.get() && browser_handler_->GetBrowser().get())
	{
		// Request that the main browser close.
		browser_handler_->GetBrowserHost()->CloseBrowser(true);
		browser_handler_->SetHostWindow(NULL);
		browser_handler_->SetHandlerDelegate(NULL);
	}
}

浏览器控件销毁 会调用CloseBrowser

从而引起OnBeforeClose,在此改变浏览器计数

结束进程时,不要直接调用::PostQuitMessage,因为这时可能还有浏览器对象没有消息

应该等所有浏览器对象都销毁后再调用::PostQuitMessage

// 当我们需要结束进程时,千万不要直接调用::PostQuitMessage,这是可能还有浏览器对象没有消息
// 应该等所有浏览器对象都销毁后再调用::PostQuitMessage
void CefManager::PostQuitMessage(int nExitCode)
{
#if !defined(SUPPORT_CEF)
	::PostQuitMessage(nExitCode);
	return;
#endif
	if (browser_count_ == 0)
	{
		Post2UI([nExitCode]()
	 	{
			::PostQuitMessage(nExitCode);
	 	});
	}
	else
	{
		auto cb = [nExitCode]()
		{
			CefManager::GetInstance()->PostQuitMessage(nExitCode);
		};
		nbase::ThreadManager::PostDelayedTask(kThreadUI, cb, nbase::TimeDelta::FromMilliseconds(500));
	}
}

 

实例:

DestroyAllCefWindows()
{
	if (m_pCefPopup)
	{
		DestroyWindow(m_pCefPopup->GetHWND());//::SendMessage(m_pCefPopup->GetHWND(), WM_CLOSE, 0, 0); //发送关闭窗口的消息WM_CLOSE
		m_pCefPopup = NULL;
	}
	if (m_pCefForm)
	{
		::SendMessage(m_pCefForm->GetHWND(), WM_CLOSE, 0, 0);//	DestroyWindow(m_pCefForm->GetHWND());//	::SendMessage(m_pCefForm->GetHWND(), WM_CLOSE, 0, 0); //发送关闭窗口的消息WM_CLOSE
		m_pCefForm = NULL;
	}
	if (m_pCefUpdate)
	{
		DestroyWindow(m_pCefUpdate->GetHWND());//::SendMessage(m_pCefUpdate->GetHWND(), WM_CLOSE, 0, 0); //发送关闭窗口的消息WM_CLOSE
		m_pCefUpdate = NULL;
	}

	HelpForm *pForm = (HelpForm*)nim_comp::WindowsManager::SingletonShow(HelpForm::kClassName, 1);

	if (pForm)
		DestroyWindow(pForm->GetHWND());


	nim_cef::CefManager::GetInstance()->PostQuitMessage(0L);
}

 

你可能感兴趣的:(CEF)