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

来源:互联网 发布:淘宝的css初始化代码 编辑:程序博客网 时间:2024/06/06 00:36

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

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

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

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

#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; }HWNDGetBrowserHostWnd() { return m_pBrowser.get()?m_pBrowser->GetHost()->GetWindowHandle():NULL; }voidSetHomePage(const wstring& strUrl) { m_strHomePage=strUrl; }const wstring& GetHomePage()const { return m_strHomePage; }wstring GetLoadingUrl();voidNavigate(const wstring& strUrl);voidCreateBrowser(HWND hParentWnd, const RECT& rect);boolIsClosing() 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;boolm_bIsClose;wstringm_strHomePage;static intm_nBrowserCount;// Include the default reference counting implementation.IMPLEMENT_REFCOUNTING(CCefHandler);IMPLEMENT_LOCKING(CCefHandler);};

对应的实现代码:

#include "stdafx.h"#include "CefHandler.h"#include <sstream>#include "util.h"#include "../include/cef_app.h"#include "../include/cef_runnable.h"intCCefHandler::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;}

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

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

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;}
消息处理主要是创建、销毁CEF对象,窗口大小改变时通知CEF窗口等:

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/6210854g_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);}
编译,运行程序,一个简单的网页就出来了,加载速度比IE那垃圾快多了,关键是不用理会兼容性问题了。



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

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

#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

感觉有所帮助,欢迎打赏(微信扫码)





5 0