Windows上使用CEF嵌入基于chrome内核浏览器小例

CEF出来很久了,使用的也很广泛的,QQ里面很多地方都是嵌入的CEF浏览器(个人资料、微博、查找……),网上的资料也挺多的,大家可以搜搜看。

首先是下载CEF代码编译,通过里面的那两个例子你也可以依葫芦画瓢的。官方下载地址:http://cefbuilds.com/

这里推荐一个很详细的解说:http://www.cnblogs.com/think/archive/2011/10/06/CEF-Introduce.html

重载CEF的各种“消息”处理类,当你需要自己处理或者自定义这些消息时,才需要重载它们,重载后一定要重写相应的虚函数返回this指针。估计内部是有这些个回调类对象指针,不返回this的话默认就是NULL了,就会执行内部默认的那套机制。

<span style="font-family:Microsoft YaHei;font-size:12px;">#pragma once
#include "include/cef_client.h"
#include <list>
#include <string>
using std::wstring;

class CCefHandler :
	public CefClient,
    public CefDisplayHandler,
    public CefLifeSpanHandler,
	public CefLoadHandler,
	public CefRequestHandler,
	public CefContextMenuHandler,
	public CefDownloadHandler
{
public:
	CCefHandler(const wstring& strUrl=L"");
	virtual ~CCefHandler();
	//自定义方法
	CefRefPtr<CefBrowser> GetBrowser() { return m_pBrowser; }
	CefRefPtr<CefFrame>	GetMainFram() { return m_pBrowser.get()?m_pBrowser->GetMainFrame():NULL; }
	HWND	GetBrowserHostWnd() { return m_pBrowser.get()?m_pBrowser->GetHost()->GetWindowHandle():NULL; }
	void	SetHomePage(const wstring& strUrl) { m_strHomePage=strUrl; }
	const wstring& GetHomePage()const { return m_strHomePage; }
	wstring GetLoadingUrl();
	void	Navigate(const wstring& strUrl);
	void	CreateBrowser(HWND hParentWnd, const RECT& rect);
	bool	IsClosing() const { return m_bIsClose; }

  //凡是继承了的处理功能都在这里返回this指针
	virtual CefRefPtr<CefDisplayHandler>		GetDisplayHandler()		{ return this; }
	virtual CefRefPtr<CefLifeSpanHandler>		GetLifeSpanHandler()	{ return this; }
	virtual CefRefPtr<CefLoadHandler>			GetLoadHandler()		{ return this; }
	virtual CefRefPtr<CefContextMenuHandler>	GetContextMenuHandler()	{ return this; }
	virtual CefRefPtr<CefDownloadHandler>		GetDownloadHandler()	{ return this; }
  // CefDisplayHandler methods:
  virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title);
  virtual void OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url);
  virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text);
  virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value);

  // CefLifeSpanHandler methods:
  virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 	  const CefString& target_url, const CefString& target_frame_name, const CefPopupFeatures& popupFeatures, 	  CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, 	  bool* no_javascript_access);
  virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser);
  virtual bool DoClose(CefRefPtr<CefBrowser> browser);
  virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser);

  // CefLoadHandler methods:
  virtual void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame);
  virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode);
  virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl);

  // Request that all existing browser windows close.
  void CloseAllBrowsers(bool force_close);
  //
  virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 	  CefRefPtr<CefRequest> request, bool is_redirect)
  {
		  //return true;
		  return false;
  }

  virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
	  CefRefPtr<CefFrame> frame,
	  CefRefPtr<CefRequest> request) {
		  return false;
  }

  //菜单处理
  virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 	  CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model);

  virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 	  CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags);

  //下载处理
  virtual void OnBeforeDownload( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, 	  const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback);

  virtual void OnDownloadUpdated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, 	  CefRefPtr<CefDownloadItemCallback> callback);
private:
	typedef std::list<CefRefPtr<CefBrowser> > BrowserList;
	BrowserList browser_list_;
	CefRefPtr<CefBrowser>	m_pBrowser;
	bool	m_bIsClose;
	wstring	m_strHomePage;
	static int	m_nBrowserCount;
	// Include the default reference counting implementation.
	IMPLEMENT_REFCOUNTING(CCefHandler);
	IMPLEMENT_LOCKING(CCefHandler);
};</span>

对应的实现代码:

<span style="font-family:Microsoft YaHei;font-size:12px;">#include "stdafx.h"
#include "CefHandler.h"
#include <sstream>
#include "util.h"
#include "../include/cef_app.h"
#include "../include/cef_runnable.h"

int		CCefHandler::m_nBrowserCount = 0;
CCefHandler::CCefHandler( const wstring& strUrl/*=L""*/ )
: m_bIsClose(false)
, m_strHomePage(strUrl)
{

}

CCefHandler::~CCefHandler()
{

}

void CCefHandler::CloseAllBrowsers(bool force_close)
{
	if (!CefCurrentlyOn(TID_UI))
	{
		// Execute on the UI thread.
		CefPostTask(TID_UI, NewCefRunnableMethod(this, &CCefHandler::CloseAllBrowsers, force_close));
		return;
	}

  if (browser_list_.empty())
    return;

  BrowserList::const_iterator it = browser_list_.begin();
  for (; it != browser_list_.end(); ++it)
    (*it)->GetHost()->CloseBrowser(force_close);
}

wstring CCefHandler::GetLoadingUrl()
{
	CefRefPtr<CefFrame> pMainFram=GetMainFram();
	return pMainFram.get()?pMainFram->GetURL():L"";
}

void CCefHandler::Navigate( const wstring& strUrl )
{
	CefRefPtr<CefFrame> pMainFram=GetMainFram();
	if ( pMainFram.get() )
		pMainFram->LoadURL(strUrl.c_str());
}

void CCefHandler::CreateBrowser( HWND hParentWnd, const RECT& rect )
{
	CefWindowInfo info;
	CefBrowserSettings settings;
	static wchar_t* pCharset = L"GB2312";
	settings.default_encoding.str = pCharset;
	settings.default_encoding.length = wcslen(pCharset);
	info.SetAsChild(hParentWnd, rect);
	CefBrowserHost::CreateBrowser(info, this, m_strHomePage.c_str(), settings, NULL);
}

//****************************************************
//菜单加载接口
void CCefHandler::OnBeforeContextMenu( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 									  CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model )
{
	//在这里,我添加了自己想要的菜单
	cef_context_menu_type_flags_t flag =   params->GetTypeFlags();
	if ( flag & CM_TYPEFLAG_PAGE )
	{//普通页面的右键消息
		model->SetLabel(MENU_ID_BACK, L"后退");
		model->SetLabel(MENU_ID_FORWARD, L"前进");
		model->SetLabel(MENU_ID_VIEW_SOURCE, L"查看源代码");
		model->SetLabel(MENU_ID_PRINT, L"打印");
		model->SetLabel(MENU_ID_RELOAD, L"刷新");
		model->SetLabel(MENU_ID_RELOAD_NOCACHE, L"强制刷新");
		model->SetLabel(MENU_ID_STOPLOAD, L"停止加载");
		model->SetLabel(MENU_ID_REDO, L"重复");
	}
	if ( flag & CM_TYPEFLAG_EDITABLE)
	{//编辑框的右键消息
		model->SetLabel(MENU_ID_UNDO, L"撤销");
		model->SetLabel(MENU_ID_REDO, L"重做");
		model->SetLabel(MENU_ID_CUT, L"剪切");
		model->SetLabel(MENU_ID_COPY, L"复制");
		model->SetLabel(MENU_ID_PASTE, L"粘贴");
		model->SetLabel(MENU_ID_DELETE, L"删除");
		model->SetLabel(MENU_ID_SELECT_ALL, L"全选");
	}
}

bool CCefHandler::OnContextMenuCommand( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 									   CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags )
{
	return false;
}

//****************************************************
//网页加载状态回调接口
void CCefHandler::OnLoadStart( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame )
{

}

void CCefHandler::OnLoadEnd( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode )
{
	//CefRefPtr<CefV8Context> v8 = frame->GetV8Context();
}

void CCefHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 							  ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl)
{
	REQUIRE_UI_THREAD();
	// Don't display an error for downloaded files.
	if (errorCode == ERR_ABORTED)
		return;
	// Display a load error message.
	std::wstringstream ss;
	//std::wstring
	ss << L"<html><body bgcolor=\"white\">"
		L"<h2>Failed to load URL " << std::wstring(failedUrl) <<
		L" with error " << std::wstring(errorText) << L" (" << errorCode <<
		L").</h2></body></html>"<<'\0';
	frame->LoadString(ss.str(), failedUrl);
}

//****************************************************
//状态改变回调接口
void CCefHandler::OnTitleChange( CefRefPtr<CefBrowser> browser, const CefString& title )
{

}

void CCefHandler::OnAddressChange( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url )
{

}

bool CCefHandler::OnTooltip( CefRefPtr<CefBrowser> browser, CefString& text )
{
	return false;
}

void CCefHandler::OnStatusMessage( CefRefPtr<CefBrowser> browser, const CefString& value )
{

}

//****************************************************
//网页生命周期回调接口
bool CCefHandler::OnBeforePopup( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 		const CefString& target_url, const CefString& target_frame_name, const CefPopupFeatures& popupFeatures, 		CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, 		bool* no_javascript_access )
{
	//这里使用默认浏览器打开网页,避免CEF重新创建窗口
	ShellExecute(NULL, L"open", target_url.c_str(), NULL, NULL, SW_SHOW);
	//return false;//创建新窗口
	return true; //禁止创建新的窗口
}

void CCefHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
	REQUIRE_UI_THREAD();
	// Add to the list of existing browsers.
	browser_list_.push_back(browser);
	AutoLock scopLock(this);
	if ( ! m_pBrowser.get() )
		m_pBrowser=browser;
	m_nBrowserCount++;
}

bool CCefHandler::DoClose(CefRefPtr<CefBrowser> browser)
{
	REQUIRE_UI_THREAD();
	// Closing the main window requires special handling. See the DoClose()
	// documentation in the CEF header for a detailed destription of this
	// process.
	if (browser_list_.size() == 1) {
		// Set a flag to indicate that the window close should be allowed.
		m_bIsClose = true;
	}

	// Allow the close. For windowed browsers this will result in the OS close
	// event being sent.
	return false;
}

void CCefHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
	REQUIRE_UI_THREAD();
	// Remove from the list of existing browsers.
	BrowserList::iterator bit = browser_list_.begin();
	for (; bit != browser_list_.end(); ++bit) {
		if ((*bit)->IsSame(browser)) {
			browser_list_.erase(bit);
			break;
		}
	}
	if (browser_list_.empty()) {
		// All browser windows have closed. Quit the application message loop.
		CefQuitMessageLoop();
	}
}

void CCefHandler::OnBeforeDownload( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, 		const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback )
{
	int i=0;
}

void CCefHandler::OnDownloadUpdated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, 		CefRefPtr<CefDownloadItemCallback> callback )
{
	//取消CEF内部下载文件,使用默认浏览器打开链接去下载,下载过程就不需要我们关心了,毕竟不是做浏览器
	callback->Cancel();
	CefString strUrl = download_item->GetURL();
	ShellExecute(NULL, L"open", strUrl.c_str(), NULL, NULL, SW_SHOW);
	int i = 0;
}
</span>

然后是实现CefApp类的重载,没有实际的处理功能,在此忽略。

使用时,创建一个win32项目,然后修改WinMain函数:

<span style="font-family:Microsoft YaHei;font-size:12px;">CefRefPtr<CCefHandler> g_handler;
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
 	// TODO: 在此放置代码。
	CefMainArgs main_args(hInstance);
	CefRefPtr<CCefAppEx> app(new CCefAppEx);
	int exit_code = CefExecuteProcess(main_args, app.get());
	if (exit_code >= 0) {
		return exit_code;
	}
	CefSettings settings;
	settings.single_process = true;
	//settings.multi_threaded_message_loop = true;
	CefInitialize(main_args, settings, app.get());
	//if ( strCmd.size() == 0 )
	HACCEL hAccelTable;
	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_CEFDEMO, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);
	// 执行应用程序初始化:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}
	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFDEMO));
	CefRunMessageLoop();
	CefShutdown();
	return 0;
}</span>

消息处理主要是创建、销毁CEF对象,窗口大小改变时通知CEF窗口等:

<span style="font-family:Microsoft YaHei;font-size:12px;">LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_CREATE:
		{//http://blog.csdn.net/wongson/article/details/6210854
			g_handler=new CCefHandler(L"www.qq.com");
			RECT rect;
			::GetClientRect(hWnd, &rect);
			g_handler->CreateBrowser(hWnd, rect);
			break;
		}
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择:
		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default: break;
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: 在此添加任意绘图代码...
		EndPaint(hWnd, &ps);
		break;
	case WM_SIZE:
		{
			if ( wParam == SIZE_MINIMIZED
				|| NULL == g_handler
				|| NULL == g_handler->GetBrowserHostWnd() )
				break;
			HWND hBrowserWnd=g_handler->GetBrowserHostWnd();
			RECT rect;
			::GetClientRect(hWnd, &rect);
			::MoveWindow(hBrowserWnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
			break;
		}
	case WM_CLOSE:
		{
			if ( g_handler.get() && !g_handler->IsClosing() )
			{
				wstring strUrl=g_handler->GetLoadingUrl();
				CefRefPtr<CefBrowser> pBrowser=g_handler->GetBrowser();
				if ( pBrowser.get() )
					pBrowser->GetHost()->CloseBrowser(true);
			}
			break;
		}
	default: break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}</span>

编译,运行程序,一个简单的网页就出来了,加载速度比IE那垃圾快多了,关键是不用理会兼容性问题了。

最后记得带上CEF的一大堆DLL,这个是必须的,如果网页需要播放视频,需要新建一个plugins文件夹,放入视频播放插件NPSWF32.dll。

需要链接的CEF动态链接库:

<span style="font-family:Microsoft YaHei;font-size:12px;">#ifdef _DEBUG
	#pragma comment(lib, "..\\LibCef\\Debug\\libcef")
#pragma comment(lib, "..\\LibCef\\Debug\\libcef_dll_wrapper")
#else
	#pragma comment(lib, "..\\LibCef\\Release\\libcef")
#pragma comment(lib, "..\\LibCef\\Release\\libcef_dll_wrapper")
#endif</span>
时间: 2024-10-20 05:54:56

Windows上使用CEF嵌入基于chrome内核浏览器小例的相关文章

python selenium中如何测试360等基于chrome内核的浏览器

转自:https://blog.csdn.net/five3/article/details/50013159 直接上代码,注意是基于chrome内核的浏览器,基于ie的请替换其中的chrome方法为ie,但自己未尝试过,如果有结果可以告知! from selenium.webdriver.chrome.options import Optionsfrom selenium import webdriverfrom selenium.webdriver.common.keys import Ke

[IE编程] 多页面基于IE内核浏览器的代码示例

有不少人发信问这个问题,我把答案贴在这里: 建议参考 WTL (Windows Template Library) 的代码示例工程TabBrowser  (在WTL目录/Samples/TabBrowser 下面).该工程演示了如何用WTL + IE WebBrowser接口开发一个多Tab的IE内核浏览器, 并演示如何用ATL的IDispEventSimpleImpl监听DWebBrowserEvents2 事件, 代码简洁易懂,很有参考价值. WTL 是微软的开源项目,可以去 http://

C# 开发Chrome内核浏览器(WebKit.net)

http://www.cnblogs.com/linyijia/p/4045333.html WebKit.net是对WebKit的.Net封装,使用它.net程序可以非常方便的集成和使用webkit作为加载网页的容器.这里介绍一下怎么用它来显示一个网页这样的一个最简单的功能. 自制浏览器C#chrome内核

基于Chrome内核(WebKit内核)定制开发DoNet浏览器

1.    源起 a)     定制.Net浏览器 本人是一名C#开发者,而作为C#开发者,做客户端应用中最头痛的一件事就是没有一个好的UI解决方案, WinFrom嘛,效率虽然还不错,但是做一些特殊的效果,完全应付不来,比如透明控件.比FPS太低有时候界面闪动得厉害.而WPF呢,内用内存又太高,效率有时候跟不上,而且还可能会出现内存泄露!出于以上的原因,博主一直在寻找一个好的UI解决方案,最终选定CEF.(至于CEF是什么我就不解释了,可以百度!),在C#中CEF的一个开源项目,名称叫做CEF

基于chrome内核的.NET开发资源

chrome Frame: 让IE有一颗chrome的心,看起来不错,但我没有深入研究这个东西. http://www.google.com/chromeframe?hl=zh-CN&quickenable=true https://developers.google.com/chrome/chrome-frame/ WebKit.Net 已经有一段时间没人更新这个开源项目了,没有研究过 http://sourceforge.net/projects/webkitdotnet/ CEF 研究过,

在 .NET 中开发基于 Chrome 内核的浏览器-创建一个简单浏览器

首先在 http://www.cftea.com/tools/downloads/Cef.zip 下载文件包. 一.将文件解压拖入到 Visual Studio 对应的 WinForm 项目中. 二.在解决方案中,在这些文件上右键,选择属性,在“复制到输出目录”中选择“始终复制”(不要忘了 locales 中的文件也要这样操作). 三.项目上右键添加引用:CefSharp.dll.CefSharp.WinForms.dll 四.在 WinForm 相应的位置使用类似如下的代码: [csharp]

chrome内核浏览器缓存资源找回方法

曾几何时,用chrome浏览器看了某个图片,网页,视频等,当时没保存,后来再怎么找都找不到了,chrome还把缓存加密了,不能像ie那样找回,这世上有买后悔药的吗?还真有! 搜索chromeCacheView即可. 软件是英文的,使用方法自己看单词.提示:可以一键复制出来的. 一个只有65kb的小软件,却能在关键时候帮上你的大忙. ps,随笔记事,以免遗忘,不是软件推广哦,这种软件也不需要推广,连开发者都没有了,也不是收费的...

C# winform开发嵌套Chrome内核浏览器(WebKit.net)开发(一)

WebKit.net是对WebKit的.Net封装, 使用它.net程序可以非常方便的集成和使用webkit作为加载网页的容器. 首先 下载WebKit.net 的bin文件. 然后 新建一个WindowsForms工程. 然后把下载好的webkit.net bin目录下的所有文件复制到新建工程的bin/Debug/目录下. 添加引用,通过浏览添加对"WebKitBrowser.dll"的引用. 放入以后的效果 双击vs项目中Form1的窗体进入代码,写下这几行代码: private

黄聪:C# 开发Chrome内核浏览器(WebKit.net)

WebKit.net是对WebKit的.Net封装,使用它.net程序可以非常方便的集成和使用webkit作为加载网页的容器.这里介绍一下怎么用它来显示一个网页这样的一个最简单的功能. 第一步: 下载WebKit.net 的bin文件.别小看这一步,你不一定能下载成功,原因你懂的. WebKit.net 的主页是http://webkitdotnet.sourceforge.net/ 直接下载0.5版本的windows bin文件地址为:https://sourceforge.net/proje