码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2015-02-26 16:40:38      阅读:2401      评论:0      收藏:0      [点我收藏+]

标签:

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>


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

标签:

原文地址:http://blog.csdn.net/mfcing/article/details/43953433

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!