Duilib_CEF桌面软件实战之Duilib嵌入CEF

内容分享6天前发布
0 0 0

上一篇我们已经把duilib嵌入到win32程序里面了,现在把CEF也嵌入进去。

Duilib_CEF桌面软件实战之Duilib嵌入CEF

先把编译好的CEF源码存放到项目里面。在cef_binary_138.0.29+gae7ee9b+chromium-138.0.7204.169_windows32uild estscefsimpleDebug路径下把编译好的文件拷贝到我们自己项目程序目录下:

Duilib_CEF桌面软件实战之Duilib嵌入CEF

然后右击项目–>属性–>VC++目录添加CEF文件路径:

包含目录:

..cef_binary_138.0.29+gae7ee9b+chromium-138.0.7204.169_windows32
..cef_binary_138.0.29+gae7ee9b+chromium-138.0.7204.169_windows32 ests

库目录:

..cef_binary_138.0.29+gae7ee9b+chromium-138.0.7204.169_windows32uildlibcef_dll_wrapperDebug
..cef_binary_138.0.29+gae7ee9b+chromium-138.0.7204.169_windows32Debug

Duilib_CEF桌面软件实战之Duilib嵌入CEF

这样做是为了可以在项目中引用CEF的库文件和头文件。

在framework.h中把cef库文件添加进去:

#pragma comment(lib, “libcef_dll_wrapper.lib”)
#pragma comment(lib, “libcef.lib”)

创建Cef_App.cpp Cef_App.h与Cef_Handler.cpp Cef_Handler.h。里面的内容基本就是cefsimple里simple_app.cc  simple_app.h与simple_handler.cc simple_handler.h的内容。



// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
 
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#include"Cef_undef.h"
#include "include/cef_app.h"
#include<string>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
 
 
class CCef_app
	: public CefApp
	, public CefBrowserProcessHandler
	, public CefRenderProcessHandler
{
public:
	CCef_app();
	virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
		override {
		return this;
	}
	// 正确实现GetRenderProcessHandler方法这继承必须放到app里面放到handl里会报错
	virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
		return this;
	}
	virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
		CefRefPtr<CefFrame> frame, 
		CefRefPtr<CefV8Context> context) override;
	virtual void OnBeforeCommandLineProcessing(
		const CefString& process_type,
		CefRefPtr<CefCommandLine> command_line);
	virtual void OnContextInitialized() override;
private:
	IMPLEMENT_REFCOUNTING(CCef_app);
};
 
#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_


// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/cef_browser.h"
#include <string>
#include<tchar.h>
#include "Cef_app.h"
#include"Cef_Handler.h"
#include "cefsimple/simple_handler.h"
#include "include/cef_command_line.h"
#include "include/wrapper/cef_helpers.h"
 
using namespace std;
 
 
CCef_app::CCef_app()
{
 
}
void CCef_app::OnBeforeCommandLineProcessing(
	const CefString& process_type,
	CefRefPtr<CefCommandLine> command_line)
{
	command_line->AppendSwitch("in-process-gpu");
}
//这是渲染进程的代码不好调试
void  CCef_app::OnContextCreated(CefRefPtr<CefBrowser> browser,
	CefRefPtr<CefFrame> frame,
	CefRefPtr<CefV8Context> context)
{
	
}
 
void CCef_app::OnContextInitialized() {
 
	//只运行在UI线程上
	CEF_REQUIRE_UI_THREAD();
	
}


// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
 
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#include "Cef_App.h"
#include "include/cef_client.h"
#include "include/base/cef_logging.h"
#include <list>
#include "include/base/cef_callback.h"
#include "include/wrapper/cef_closure_task.h"
 
class Cef_Handler
	: public CefClient
	, public CefDisplayHandler
	, public CefLifeSpanHandler
	, public CefRequestHandler
	, public CefLoadHandler
{
public:
	 Cef_Handler();
	virtual ~Cef_Handler();
	//必须先调用此回调才能使用CefLoadHandler中的回调函数
	virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override
	{
		return this;
	}
	//必须先调用此回调才能使用CefRequestHandler中的回调函数
	virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override
	{
		return this;
	}
	virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override
	{
		return this;
	}
	virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override
	{
		return this;
	}
	virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) override;
	virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
	virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
	static Cef_Handler* GetInstance();
	// Request that all existing browser windows close.
	void CloseAllBrowsers(bool force_close);
	CefWindowHandle			GetBrowserhWnd()	const;
	CefRefPtr<CefBrowser>	GetBrowser()		const;
	CefRefPtr<CefFrame>		GetMainFrame()		const;
	int						GetIdentifier()		const;
	HWND					GetPaintWindow()	const;
 
	HWND					m_windowHwnd = NULL;
	CefRefPtr<CefBrowser>	m_pBrowser;
 
private:
	typedef std::list<CefRefPtr<CefBrowser> > BrowserList;
	BrowserList browser_list_;
	HWND					m_hParentWnd;
private:
 
	IMPLEMENT_REFCOUNTING(Cef_Handler);
};
 
 
#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_


// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include"framework.h"
#include "Cef_Handler.h"
#include <sstream>
#include <string>
#include "include/base/cef_bind.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
 
 
using namespace std;
namespace {
 
	Cef_Handler* g_instance = NULL;
 
}  // namespace
// static
Cef_Handler* Cef_Handler::GetInstance() {
	return g_instance;
}
Cef_Handler::Cef_Handler()
{
	DCHECK(!g_instance);
	g_instance = this;
}
 
Cef_Handler::~Cef_Handler()
{
	g_instance = NULL;
}
void Cef_Handler::OnTitleChange(CefRefPtr<CefBrowser> browser,
	const CefString& title)
{
	CEF_REQUIRE_UI_THREAD();
	CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
	SetWindowText(hwnd, title.ToWString().c_str());
}
void Cef_Handler::CloseAllBrowsers(bool force_close) {
	
}
void Cef_Handler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
	CEF_REQUIRE_UI_THREAD();
	m_windowHwnd = browser->GetHost()->GetWindowHandle();
	m_pBrowser = browser;
	// Add to the list of existing browsers.
	browser_list_.push_back(browser);
}
 
void Cef_Handler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
	CEF_REQUIRE_UI_THREAD();
 
}
CefRefPtr<CefBrowser> Cef_Handler::GetBrowser() const
{
 
	if (!browser_list_.empty())
	{
		return  browser_list_.front();
	}
	return nullptr;
 
 
	//	return m_pBrowser;
}
CefWindowHandle Cef_Handler::GetBrowserhWnd() const
{
	return GetBrowser().get() != NULL ? GetBrowser()->GetHost()->GetWindowHandle() : NULL;
}
CefRefPtr<CefFrame> Cef_Handler::GetMainFrame() const
{
	return GetBrowser().get() != NULL ? GetBrowser()->GetMainFrame() : nullptr;
}
 
int Cef_Handler::GetIdentifier() const
{
	return GetBrowser() ? GetBrowser()->GetIdentifier() : -1;
}
HWND Cef_Handler::GetPaintWindow() const
{
	return m_hParentWnd;
}

在CEF中如果继承了哪个基类第一步需要先获取该类的指针。

GetBrowserProcessHandler:提供自定义浏览器进程实体控制器的能力。
GetRenderProcessHandler:提供自定义renderer进程实体控制器的能力。

然后在main函数把加载CEF的代码加上试试:



int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    //Cef
	wstring LocalStoragePath = L"D:\COOKIES";
#if defined(WIN32) && !defined(UNDER_CE)
	HRESULT Hr = ::CoInitialize(NULL);
#else
	HRESULT Hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
#endif
	if (FAILED(Hr)) return 0;
	CefMainArgs args(hInstance);
 
	//CefEnableHighDPISupport();
	//填充这个结构体,定制CEF的行为。
	void* sandbox_info = NULL;
	CefSettings settings;
	CefSettingsTraits::init(&settings);
	settings.multi_threaded_message_loop = true;
	settings.no_sandbox = true; // 测试环境开启
 
	//settings.windowless_rendering_enabled = true;
	CefString(&settings.locale).FromWString(L"zh-CN");
	CefString(&settings.cache_path).FromWString(LocalStoragePath.c_str());
	
 
	#if _DEBUG
		CefString(&settings.log_file).FromWString(L"debug.log");
		settings.log_severity = LOGSEVERITY_DEFAULT;
	#endif
	CefString(&settings.user_agent) = L"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.2228.0 Safari/537.36";
 
	//创建CefApp实例
	CefRefPtr<CCef_app> app(new CCef_app);
	int exitCode = CefExecuteProcess(args, app, sandbox_info);
	if (exitCode >= 0)
	{
		return exitCode;
	}
 
	CefInitialize(args, settings, app.get(), sandbox_info);
	
    CPaintManagerUI::SetInstance(hInstance);
 
    CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));
   
    CFrameWnd duiFrame(L"frame.xml");
    duiFrame.Create(NULL, _T("FrameWnd"), UI_WNDSTYLE_DIALOG | WS_MINIMIZEBOX, WS_EX_WINDOWEDGE);
    duiFrame.ShowModal();
}

编译一下试试看:报错了。

Duilib_CEF桌面软件实战之Duilib嵌入CEF

解决这错误的方法如下图:

Duilib_CEF桌面软件实战之Duilib嵌入CEF

还有一个错误很莫名其妙GetNextSibling()函数报错,但是这是CEF自己的函数按理应该不会,查了资料原来是和windows里面头文件冲突。解决方案就是创建一个头文件Cef_undef.h在Cef_App.h里面引入它就可以了



#pragma once
 
 
#ifdef GetNextSibling
#undef GetNextSibling
#endif
 
#ifdef GetFirstChild
#undef GetFirstChild
#endif
 
// 其他可能冲突的宏
#ifdef GetNextSibling
#undef GetNextSibling
#endif

终于不报错了,但是大家会不会有个疑问,CEF和Duilib都加入到项目里面了,但是好像它们两并没有关联起来。我们现在就开始关联吧。

首先我们修改frame.xml内容添加:<cefbrowser  name=”Cef_Browser”/>



<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Window size="800,600" >
<VerticalLayout bkcolor="#FF87CEEB">
	<HorizontalLayout>
		<cefbrowser  name="Cef_Browser"/>
	</HorizontalLayout>
</VerticalLayout>
</Window>

然后在项目里面创建CCefBrowserUI.cpp与CCefBrowserUI.h这个类是继承Duilib里面CControlUI但是是我们自己给UI界面扩展的一个浏览器控件。



#pragma once
#include"framework.h"
#include"Cef_Handler.h"
#ifdef _DEBUG
#define _ITERATOR_DEBUG_LEVEL 0	// speedup iterator operations while debugging
#endif
class CCefBrowserUI : public CControlUI
{
public:
	CCefBrowserUI();
	~CCefBrowserUI();
 
	virtual LPCTSTR GetClass() const;
	virtual LPVOID GetInterface(LPCTSTR pstrName);
	//这个一定要设置,不然控件无法显示
	virtual void SetPos(RECT rc, bool bNeedInvalidate = true);
	//virtual void Move(SIZE szOffset, bool bNeedInvalidate = true);
	virtual void SetInternVisible(bool bVisible = true);
	//virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled);
	virtual bool		DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
 
	CefRefPtr<CefBrowser> GetBrowser()
	{
		if (m_Browser)
		{
			return m_Browser->GetBrowser();
		}
		else
		{
			CreateBrowser(L"about:blank");
 
		}
		return m_Browser->GetBrowser();
	}
 
	CefRefPtr<CefFrame> GetMainFrame()
	{
		if (m_Browser)
		{
			return m_Browser->GetMainFrame();
		}
		else
		{
			CreateBrowser(L"about:blank");
		}
		return m_Browser->GetMainFrame();
	}
 
	void CloseAllBrowser();
	void LoadUrl(const CefString& url);
	void CreateBrowser(const CefString& szHomePage);
	//当界面控件太少时,GetPos第一次获取的大小为0 DoPaint执行少导致cef绘制失败,需要手动设置RECT大小
	void CreateBrowser(RECT ct, const CefString& szHomePage);
 
	//protected:
private:
	CefRefPtr<Cef_Handler> m_Browser = nullptr;
	
};


#include "CCefBrowserUI.h"
#include<tchar.h>
 
 
CCefBrowserUI::CCefBrowserUI() {
}
 
CCefBrowserUI::~CCefBrowserUI() {
	//m_pManager->RemoveMessageFilter(this);
	if (m_Browser != nullptr)
	{
		m_Browser->GetBrowser()->GetHost()->CloseBrowser(true);
		m_Browser = nullptr;
	}
}
 
LPCTSTR CCefBrowserUI::GetClass() const {
	return _T("CefBrowserUI");
}
 
LPVOID CCefBrowserUI::GetInterface(LPCTSTR pstrName)
{
	if (_tcsicmp(pstrName, _T("Cef_Browser")) == 0)
	{
		return static_cast<CCefBrowserUI*>(this);
	}
	return CControlUI::GetInterface(pstrName);
}
 
void CCefBrowserUI::SetPos(RECT rc, bool bNeedInvalidate /* = true */)
{
	CControlUI::SetPos(rc, bNeedInvalidate);
	if (m_Browser.get())
	{
		CefRefPtr<CefBrowser> browser = m_Browser->GetBrowser();
		DuiLib::CDuiRect rc = GetPos();
		if (browser && !rc.IsNull())
		{
			::SetWindowPos(browser->GetHost()->GetWindowHandle(),
				NULL, rc.left, rc.top, rc.GetWidth(), rc.GetHeight(), SWP_NOZORDER | SWP_NOACTIVATE);
		}
	}
}
 
void CCefBrowserUI::SetInternVisible(bool bVisible)
{
}
 
bool CCefBrowserUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
{
	if (IsVisible() && GetBrowser().get())
	{
		HWND hBrowserWnd = m_Browser->GetBrowserhWnd();
		::MoveWindow(hBrowserWnd
			, m_rcItem.left
			, m_rcItem.top
			, m_rcItem.right - m_rcItem.left
			, m_rcItem.bottom - m_rcItem.top
			, true);
 
		if (!::IsWindowVisible(hBrowserWnd))
		{
			::ShowWindow(hBrowserWnd, IsVisible());
		}
	}
 
	return __super::DoPaint(hDC, rcPaint, pStopControl);
}
 
 
 
void CCefBrowserUI::CloseAllBrowser()
{
	if (m_Browser.get())
	{
		m_Browser->CloseAllBrowsers(true);
	}
}
 
void CCefBrowserUI::CreateBrowser(const CefString& szHomePage)
{
	CefWindowInfo info;
	if (m_Browser == NULL)
	{
		m_Browser = new Cef_Handler();
		if (m_Browser != NULL)
		{
			RECT rt = GetPos();
			CefRect Ret(0, 0, 1, 1);
			
			info.SetAsChild(GetManager()->GetPaintWindow(), Ret);
			info.style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
			CefBrowserSettings browserSettings;
			CefRefPtr<CefRequestContext> rc = CefRequestContext::GetGlobalContext();
			//browserSettings.image_loading = STATE_DISABLED;
			//browserSettings.remote_fonts = STATE_DISABLED;
			CefBrowserHost::CreateBrowser(info, m_Browser.get(), szHomePage, browserSettings, nullptr, rc);
		}
	}
	if (m_Browser->GetMainFrame().get())
	{
		m_Browser->GetMainFrame()->LoadURL(szHomePage.c_str());
	}
	return;
}
void CCefBrowserUI::CreateBrowser(RECT ct, const CefString& szHomePage)
{
	CefWindowInfo info;
	if (m_Browser == NULL)
	{
		m_Browser = new Cef_Handler();
		if (m_Browser != NULL)
		{
			RECT rt = GetPos();
			CefRect Ret(rt.left, rt.right, rt.top, rt.bottom);
			info.SetAsChild(GetManager()->GetPaintWindow(), Ret);
			CefBrowserSettings browserSettings;
			CefRefPtr<CefRequestContext> rc = CefRequestContext::GetGlobalContext();
			CefBrowserHost::CreateBrowser(info, m_Browser.get(), szHomePage, browserSettings, nullptr, rc);
		}
	}
	else
	{
		if (m_Browser->GetMainFrame().get())
		{
			m_Browser->GetMainFrame()->LoadURL(szHomePage.c_str());
		}
	}
	return;
}
void CCefBrowserUI::LoadUrl(const CefString& url)
{
	if (m_Browser.get())
	{
		CefRefPtr<CefFrame> mainframe = m_Browser->GetMainFrame();
		if (mainframe)
			mainframe->LoadURL(url);
	}
}

GetInterface:获取frame.xml中扩展的cefbrowser名字。

CreateBrowser:创建浏览器实例。

LoadUrl:如果已经创建浏览器实例也可以用该函数打开网址。

好了最后一步就是我们要在CFrameWnd.cpp里面创建一个cefbrowser扩展控件这样就把CEF与Duilib界面关联起来了。



CControlUI* CFrameWnd::CreateControl(LPCTSTR pstrClassName)//创建新的控件
{
	if (_tcsicmp(pstrClassName, _T("cefbrowser")) == 0)
	{
		return  new CCefBrowserUI;
	}
	return NULL;
}

编译运行下看看,竟然崩溃了,而且是一个很莫名其妙的崩溃,堆栈也没有任何提示。在libcef.dll报错了。没办法只能到处找解决方案。

Duilib_CEF桌面软件实战之Duilib嵌入CEF

Duilib_CEF桌面软件实战之Duilib嵌入CEF

终于在CEF官网找到一个解决方案,开启GPU渲染可以解决问题:command_line->AppendSwitch(“in-process-gpu”)

最后编译下试试效果:

Duilib_CEF桌面软件实战之Duilib嵌入CEF

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...