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