標籤:
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; }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);};</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"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;}</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/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);}</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核心瀏覽器小例