CEF版本是Branch 2171 开发环境是VS2012
查看一下libcef_dll_wrapper工程属性,确定Code Generation 选择MTD(Debug) 或者MT(Release),这个设置是编译出的静态库是多线程静态链接,在其他工程中使用时,使用者的工程属性也要对应设置MTD或者MT,让二者保持一致,这样保证不会链接出错。
然后我们选择ALL_BUILD后Build,如果不出意外应该会报编译错误:
然后上网搜了一下,是编译器把警告当成错误了
参考我之前博客可以解决:http://www.cnblogs.com/chechen/p/6104879.html
CEF运行主要依赖的库就是libcef_dll_wrapper.lib和libcef.lib,其中libcef_dll_wrapper.lib是静态库,libcef.lib 动态库。
一、在MFC中嵌入CEF浏览器窗口
1.第一步
第二步:
第三步:
Finish之后,调整一下对话框的大小,把对话框上的按钮去掉。
第四步:
把include文件夹拷贝到当前目录
第五步:在上一级目录下新建两个目录bin和Lib
第六步:把CEF工程中Resources目录下的文件全部拷贝到bin目录下
第七步:把CEF工程中Debug下除两个.lib文件全部拷贝到bin目录下
第八步:把Debug目录下的libcef.lib文件和libcef_dll_wrapper\\Debug目录下的libcef_dll_wrapper.lib拷贝到Lib文件下
第九步:工程设置
第十步:在stdafx.h文件中加入队CEF库的引用和用到的头文件
#include "include/cef_app.h"
#include "include/cef_client.h"
// 添加引用CEF的库 #ifdef _DEBUG # ifdef _UNICODE # pragma comment(lib, "..\\Lib\\libcef.lib") # pragma comment(lib, "..\\Lib\\libcef_dll_wrapper.lib") # else // Release # endif #else # ifdef _UNICODE # pragma comment(lib, "..\\Lib\\libcef.lib") # pragma comment(lib, "..\\Lib\\libcef_dll_wrapper.lib") # else // Release # endif #endif
这时我编译一下,检查引用库是否正常
第十一步:实现我们自己浏览器的CefApp类
.h文件
1 #ifndef _CEFBROWSERAPP_H_ 2 #define _CEFBROWSERAPP_H_ 3 7 class CCefBrowserApp :public CefApp, 8 public CefBrowserProcessHandler 9 { 10 public: 11 CCefBrowserApp(void); 12 ~CCefBrowserApp(void); 13 14 // CefApp methods: 15 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() 16 OVERRIDE { return this; } 17 18 // CefBrowserProcessHandler methods: 19 virtual void OnContextInitialized() OVERRIDE; 20 21 private: 22 // Include the default reference counting implementation. 23 IMPLEMENT_REFCOUNTING(CCefBrowserApp); 24 }; 25 26 #endif //_CEFBROWSERAPP_H_
.cpp文件
1 #include "stdafx.h" 2 #include "CefBrowserApp.h" 3 4 5 CCefBrowserApp::CCefBrowserApp(void) 6 { 7 8 } 9 10 11 CCefBrowserApp::~CCefBrowserApp(void) 12 { 13 14 } 15 16 17 void CCefBrowserApp::OnContextInitialized() 18 { 19 20 }
第十二步:按照分析的步骤编写浏览器并嵌入到我们的MFC主窗口中,在InitInstance中初始化cef
1 /***************************************begin初始化cef*******************************************/ 2 3 void* sandbox_info = NULL; 4 CefMainArgs main_args(AfxGetApp()->m_hInstance); 5 CefRefPtr<CCefBrowserApp> spApp(new CCefBrowserApp); 6 7 // Execute the secondary process, if any. 8 int exit_code = CefExecuteProcess(main_args, spApp.get(),sandbox_info); 9 if (exit_code >= 0) 10 return exit_code; 11 CefSettings cSettings; 12 cSettings.no_sandbox = true; 13 cSettings.multi_threaded_message_loop = true; 14 // Execute the secondary process, if any. 15 CefInitialize(main_args, cSettings, spApp.get(),sandbox_info); 16 /***************************************结束初始化cef*******************************************/
第十三步:在对话框OnInitDialog函数中创建浏览器,在创建前我们先实现自己的CefClient类
.h文件
1 #ifndef _CEFBROWSERHANDLER_H_ 2 #define _CEFBROWSERHANDLER_H_ 3 4 #include <list> 5 6 class CCefBrowserHandler: public CefClient, 7 public CefDisplayHandler,//显示变化事件 8 public CefLifeSpanHandler,//Browser生命周期 9 public CefLoadHandler//加载错误事件 10 { 11 public: 12 CCefBrowserHandler(void); 13 ~CCefBrowserHandler(void); 14 15 public: 16 // CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器 17 virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE; 18 virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE; 19 virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE; 20 21 public: 22 // load handler method 23 virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; 24 25 public: 26 // display handler meethod 27 virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; 28 virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 29 virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 30 public: 31 // own method of cef browser event handler 32 void CloseAllBrowser(bool bForceClose = true); 33 protected: 34 typedef std::list<CefRefPtr<CefBrowser> > BrowserList; 35 BrowserList m_browser_list; 36 37 IMPLEMENT_REFCOUNTING(CCefBrowserHandler); 38 39 }; 40 #endif //_CEFBROWSERHANDLER_H_
.cpp文件
1 #include "stdafx.h" 2 #include "CefBrowserHandler.h" 3 #include <sstream> 4 #include <string> 5 #include "include/base/cef_bind.h" 6 #include "include/views/cef_browser_view.h" 7 #include "include/views/cef_window.h" 8 #include "include/wrapper/cef_closure_task.h" 9 #include "include/wrapper/cef_helpers.h" 10 11 CCefBrowserHandler::CCefBrowserHandler(void) 12 { 13 14 } 15 16 17 CCefBrowserHandler::~CCefBrowserHandler(void) 18 { 19 20 } 21 22 CefRefPtr<CefDisplayHandler> CCefBrowserHandler::GetDisplayHandler() 23 { 24 return this; 25 } 26 27 CefRefPtr<CefLifeSpanHandler> CCefBrowserHandler::GetLifeSpanHandler() 28 { 29 return this; 30 } 31 32 CefRefPtr<CefLoadHandler> CCefBrowserHandler::GetLoadHandler() 33 { 34 return this; 35 } 36 37 38 void CCefBrowserHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, 39 const CefString& errorText, const CefString& failedUrl) 40 { 41 CEF_REQUIRE_UI_THREAD(); 42 if (ERR_ABORTED == errorCode) 43 return ; 44 45 std::stringstream ss; 46 ss << "<html><body bgcolor=\"white\">" 47 "<h2>Failed to load URL " << std::string(failedUrl) << 48 " with error " << std::string(errorText) << " (" << errorCode << 49 ").</h2></body></html>"; 50 frame->LoadString(ss.str(), failedUrl); 51 } 52 53 void CCefBrowserHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) 54 { 55 CEF_REQUIRE_UI_THREAD(); 56 m_browser_list.push_back(browser); 57 } 58 59 bool CCefBrowserHandler::DoClose(CefRefPtr<CefBrowser> browser) 60 { 61 CEF_REQUIRE_UI_THREAD(); 62 if (1 == m_browser_list.size()) 63 { 64 } 65 return false; 66 } 67 68 void CCefBrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 69 { 70 CEF_REQUIRE_UI_THREAD(); 71 for (BrowserList::iterator bit = m_browser_list.begin(); bit != m_browser_list.end(); ++bit) 72 { 73 if ((*bit)->IsSame(browser)) { 74 m_browser_list.erase(bit); 75 break; 76 } 77 } 78 79 if (m_browser_list.empty()) 80 { 81 CefQuitMessageLoop(); 82 } 83 } 84 85 void CCefBrowserHandler::CloseAllBrowser(bool force_close) 86 { 87 if (!CefCurrentlyOn(TID_UI)) 88 { 89 CefPostTask(TID_UI,base::Bind(&CCefBrowserHandler::CloseAllBrowser, this, force_close)); 90 return; 91 } 92 93 if (m_browser_list.empty()) 94 return; 95 96 BrowserList::const_iterator it = m_browser_list.begin(); 97 for (; it != m_browser_list.end(); ++it) 98 { 99 (*it)->GetHost()->CloseBrowser(force_close); 100 } 101 }
在OnInitDialog()函数中创建浏览器
//开始创建浏览器 CRect rtBody; GetWindowRect(&rtBody); CefWindowInfo cefWindowInfo; cefWindowInfo.SetAsChild(GetSafeHwnd(), rtBody); CefBrowserSettings browserSetting; CefRefPtr<CCefBrowserHandler> objEventHandler(new CCefBrowserHandler()); CefBrowserHost::CreateBrowser(cefWindowInfo, objEventHandler.get(), _T("http://www.baidu.com"), browserSetting, NULL);
第十三步:关闭主窗口时,关闭浏览器
给对话框添加WM_DESTROY消息响应
void CMFCCefDemoDlg::OnDestroy() { CDialogEx::OnDestroy(); // TODO: Add your message handler code here CefShutdown(); }
MFCDemo转载:http://blog.csdn.net/lixiang987654321/article/details/52174121
二、在Win32窗口里嵌入CEF浏览器窗口
第一步:新建Win32项目
第二步:使用默认
第三步:修改工程属性
第四步:在stdafx.h中加入 CEF库
#ifdef _DEBUG # ifdef _UNICODE # pragma comment(lib, "..\\Lib\\libcef.lib") # pragma comment(lib,"..\\Lib\\libcef_dll_wrapper.lib") # else # //Release # endif #else # ifdef _UNICODE # //Multi_Debug # else # //Multi_Release # endif #endif
第五步:在工程目录下新建两个目录,分别为bin和Lib
第六步:把CEF工程中Resources目录下的文件全部拷贝到bin目录下
第七步:把CEF工程中Debug下除两个.lib文件全部拷贝到bin目录下
第八步:把Debug目录下的libcef.lib文件和libcef_dll_wrapper\\Debug目录下的libcef_dll_wrapper.lib拷贝到Lib文件下
第九步:工程设置-->指定生成的exe文件的路径
第十步:实现自己的CefApp
.h
1 #ifndef _MYCEFAPP_H_ 2 #define _MYCEFAPP_H_ 3 4 #include "include/cef_app.h" 5 6 class CMyCefApp: public CefApp, 7 public CefBrowserProcessHandler { 8 9 public: 10 CMyCefApp(void); 11 ~CMyCefApp(void); 12 13 // CefApp methods: 14 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() 15 OVERRIDE { return this; } 16 17 // CefBrowserProcessHandler methods: 18 virtual void OnContextInitialized() OVERRIDE; 19 20 private: 21 // Include the default reference counting implementation. 22 IMPLEMENT_REFCOUNTING(CMyCefApp); 23 }; 24 25 26 #endif//_MYCEFAPP_H_
.cpp
1 #include "stdafx.h" 2 #include "MyCefApp.h" 3 4 5 CMyCefApp::CMyCefApp(void) 6 { 7 8 } 9 10 11 CMyCefApp::~CMyCefApp(void) 12 { 13 14 } 15 16 17 void CMyCefApp::OnContextInitialized() { 18 19 }
第十二步:实现自己的Handler类
.h
1 #pragma once 2 #include "include/cef_client.h" 3 #include <list> 4 #include <string> 5 using std::wstring; 6 7 class CCefHandler: 8 public CefClient, 9 public CefDisplayHandler, 10 public CefLifeSpanHandler, 11 public CefLoadHandler 12 { 13 public: 14 CCefHandler(); 15 16 virtual ~CCefHandler(void); 17 18 // Provide access to the single global instance of this object. 19 static CCefHandler* GetInstance(); 20 21 // CefClient methods: 22 virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE { 23 return this; 24 } 25 virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE { 26 return this; 27 } 28 virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { 29 return this; 30 } 31 32 // CefDisplayHandler methods: 33 virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, 34 const CefString& title) OVERRIDE; 35 36 // CefLifeSpanHandler methods: 37 virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; 38 virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 39 virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 40 41 // CefLoadHandler methods: 42 virtual void OnLoadError(CefRefPtr<CefBrowser> browser, 43 CefRefPtr<CefFrame> frame, 44 ErrorCode errorCode, 45 const CefString& errorText, 46 const CefString& failedUrl) OVERRIDE; 47 48 // Request that all existing browser windows close. 49 //void CloseAllBrowsers(bool force_close); 50 51 bool IsClosing() const { return is_closing_; } 52 53 CefRefPtr<CefBrowser> GetBrowser(){return m_browser;} 54 55 private: 56 // List of existing browser windows. Only accessed on the CEF UI thread. 57 //typedef std::list<CefRefPtr<CefBrowser> > BrowserList; 58 // BrowserList browser_list_; 59 60 CefRefPtr<CefBrowser> m_browser; 61 62 bool is_closing_; 63 64 // Include the default reference counting implementation. 65 IMPLEMENT_REFCOUNTING(CCefHandler); 66 }
.cpp
1 #include "stdafx.h" 2 #include "CefHandler.h" 3 #include <sstream> 4 #include <string> 5 7 #include "include/cef_app.h" 8 #include "include/cef_runnable.h" 9 #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_helpers.h" 10 namespace { 11 12 CCefHandler* g_instance = NULL; 13 14 } // namespace 15 16 CCefHandler::CCefHandler() 17 : is_closing_(false) 18 ,m_browser(NULL){ 20 g_instance = this; 21 } 22 23 CCefHandler::~CCefHandler() { 24 g_instance = NULL; 25 } 26 27 // static 28 CCefHandler* CCefHandler::GetInstance() { 29 return g_instance; 30 } 31 32 void CCefHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) { 33 REQUIRE_UI_THREAD(); 34 35 // Add to the list of existing browsers. 36 //browser_list_.push_back(browser); 37 38 m_browser = browser; 39 } 40 41 bool CCefHandler::DoClose(CefRefPtr<CefBrowser> browser) { 42 CEF_REQUIRE_UI_THREAD(); 43 44 // Closing the main window requires special handling. See the DoClose() 45 // documentation in the CEF header for a detailed destription of this 46 // process. 47 //if (browser_list_.size() == 1) 48 if(m_browser) 49 { 50 // Set a flag to indicate that the window close should be allowed. 51 is_closing_ = true; 52 } 53 54 // Allow the close. For windowed browsers this will result in the OS close 55 // event being sent. 56 return false; 57 } 58 59 void CCefHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, 60 const CefString& title) 61 { 62 63 } 64 65 void CCefHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) { 66 CEF_REQUIRE_UI_THREAD(); 67 68 // Remove from the list of existing browsers. 69 //BrowserList::iterator bit = browser_list_.begin(); 70 //for (; bit != browser_list_.end(); ++bit) { 71 // if ((*bit)->IsSame(browser)) { 72 // browser_list_.erase(bit); 73 // break; 74 // } 75 //} 76 77 //if (browser_list_.empty()) { 78 // // All browser windows have closed. Quit the application message loop. 79 // CefQuitMessageLoop(); 80 //} 81 82 if(m_browser->IsSame(browser)) 83 m_browser = NULL; 84 } 85 86 void CCefHandler::OnLoadError(CefRefPtr<CefBrowser> browser, 87 CefRefPtr<CefFrame> frame, 88 ErrorCode errorCode, 89 const CefString& errorText, 90 const CefString& failedUrl) 91 { 92 CEF_REQUIRE_UI_THREAD(); 93 94 // Don't display an error for downloaded files. 95 if (errorCode == ERR_ABORTED) 96 return; 97 98 // Display a load error message. 99 std::stringstream ss; 100 ss << "<html><body bgcolor=\"white\">" 101 "<h2>Failed to load URL " << std::string(failedUrl) << 102 " with error " << std::string(errorText) << " (" << errorCode << 103 ").</h2></body></html>"; 104 frame->LoadString(ss.str(), failedUrl); 105 }
第十二步:初始化CEF
1 /***************************************begin初始化cef*******************************************/ 2 3 void* sandbox_info = NULL; 4 CefMainArgs main_args(hInstance); 5 CefRefPtr<SimpleApp> spApp(new SimpleApp); 6 7 // Execute the secondary process, if any. 8 int exit_code = CefExecuteProcess(main_args, spApp.get(),sandbox_info); 9 if (exit_code >= 0) 10 return exit_code; 11 CefSettings cSettings; 12 cSettings.no_sandbox = true; 13 cSettings.multi_threaded_message_loop = true; 14 15 CefInitialize(main_args, cSettings, spApp.get(),sandbox_info); 16 /***************************************结束初始化cef*******************************************/
第十三步:在WM_CREATE消息出创建CEF浏览器窗口
先定义一个全局的Handler对象指针
CefRefPtr<CCefHandler> g_handler;
1 . . . . . . . 2 case WM_CREATE: 3 { 4 g_handler=new CCefHandler(); 5 6 7 RECT rect; 8 ::GetClientRect(hWnd, &rect); 9 CefWindowInfo info; 10 info.SetAsChild(hWnd, rect); 11 12 CefBrowserSettings settings1; 13 CefBrowserHost::CreateBrowser(info, g_handler.get(), CefString ("http://www.baidu.com"), settings1, NULL); 14 15 return 0; 16 } 17 . . . . . . .
至此你运行就可以看到效果了。。。
最后关闭,我们要在WM_CLOSE消息出做处理:
case WM_CLOSE: if (g_handler.get() && !g_handler->IsClosing()) { CefRefPtr<CefBrowser> browser = g_handler->GetBrowser(); if (browser.get()) { // Notify the browser window that we would like to close it. This // will result in a call to ClientHandler::DoClose() if the // JavaScript 'onbeforeunload' event handler allows it. browser->GetHost()->CloseBrowser(false); // Cancel the close. return 0; } } DestroyWindow(hWnd); // Allow the close. break;
最后程序退出时时要关闭CEF
三、CEF嵌入到Duilib窗口中
工程配置参考前面两种
1.实现自己的APP类
.h
1 #ifndef _CEFBROWSERAPP_H_ 2 #define _CEFBROWSERAPP_H_ 3 #include "include/cef_app.h" 4 5 class CCefBrowserApp 6 : public CefApp 7 , public CefBrowserProcessHandler 8 { 9 public: 10 CCefBrowserApp(); 11 12 virtual ~CCefBrowserApp(); 13 14 public: 15 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE { return this; }; 16 17 public: 18 // CefBrowserProcessHandler methods: 19 virtual void OnContextInitialized(); 20 21 protected: 22 23 IMPLEMENT_REFCOUNTING(CCefBrowserApp); 24 }; 25 #endif //_CEFBROWSERAPP_H_
.cpp
1 #include "CefBrowserApp.h" 2 #include "stdafx.h" 3 4 5 CCefBrowserApp::CCefBrowserApp() 6 { 7 } 8 9 CCefBrowserApp::~CCefBrowserApp() 10 { 11 } 12 13 14 void CCefBrowserApp::OnContextInitialized() 15 { 16 // do nothing here, because we will create browser in my own dialog 17 }
2.实现自己的Handler类
.h
1 #ifndef _CEFBROWSEREVENTHANDLER_H_ 2 #define _CEFBROWSEREVENTHANDLER_H_ 3 #include "include/cef_client.h" 4 #include "include/base/cef_lock.h" //线程安全 5 6 7 class CCefBrowserEventHandler 8 : public CefClient 9 , public CefDisplayHandler // 显示变化事件 10 , public CefLoadHandler // 加载错误事件 11 , public CefLifeSpanHandler // 声明周期事件 12 { 13 public: 14 CCefBrowserEventHandler(); 15 16 virtual ~CCefBrowserEventHandler(); 17 18 public: 19 // CefClient 事件处理器,如果没有对应处理器则默认使用内部处理器 20 virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE; 21 virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE; 22 virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE; 23 24 public: 25 // display handler method 26 virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE; 27 28 public: 29 // load handler method 30 virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, 31 ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; 32 33 public: 34 // display handler meethod 35 virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; 36 virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 37 virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 38 39 bool IsClosing() const { return m_bIsClosing; } 40 41 CefRefPtr<CefBrowser> GetBrowser(){return m_Browser;} 42 43 protected: 44 45 CefRefPtr<CefBrowser> m_Browser; 46 47 bool m_bIsClosing; 48 49 IMPLEMENT_REFCOUNTING(CCefBrowserEventHandler); 50 //由于CEF采用多线程架构,有必要使用锁和闭包来保证在多不同线程安全的传递数据。IMPLEMENT_LOCKING定义提供了Lock()和Unlock()方法以及AutoLock对象来保证不同代码块同步访问 51 IMPLEMENT_LOCKING(CCefBrowserEventHandler);//必须包含#include "include/base/cef_lock.h" 52 }; 53 54 #endif//_CEFBROWSEREVENTHANDLER_H_
.cpp
1 #include "CefBrowserEventHandler.h" 2 #include "stdafx.h" 3 #include <sstream> 4 #include <string> 5 #include "include/cef_app.h" 6 #include "include/wrapper/cef_closure_task.h" 7 #include "include/wrapper/cef_helpers.h" 8 9 10 CCefBrowserEventHandler::CCefBrowserEventHandler(CMainFrameWnd* pMainFrame) 11 :m_bIsClosing(false) 12 { 13 14 } 15 16 CCefBrowserEventHandler::~CCefBrowserEventHandler() 17 { 18 19 } 20 21 CefRefPtr<CefDisplayHandler> CCefBrowserEventHandler::GetDisplayHandler() 22 { 23 return this; 24 } 25 26 CefRefPtr<CefLifeSpanHandler> CCefBrowserEventHandler::GetLifeSpanHandler() 27 { 28 return this; 29 } 30 31 CefRefPtr<CefLoadHandler> CCefBrowserEventHandler::GetLoadHandler() 32 { 33 return this; 34 } 35 36 void CCefBrowserEventHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) 37 { 38 39 } 40 41 void CCefBrowserEventHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, 42 const CefString& errorText, const CefString& failedUrl) 43 { 44 CEF_REQUIRE_UI_THREAD(); 45 if (ERR_ABORTED == errorCode) 46 return ; 47 48 std::stringstream ss; 49 ss << "<html><body bgcolor=\"white\">" 50 "<h2>Failed to load URL " << std::string(failedUrl) << 51 " with error " << std::string(errorText) << " (" << errorCode << 52 ").</h2></body></html>"; 53 frame->LoadString(ss.str(), failedUrl); 54 } 55 56 void CCefBrowserEventHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) 57 { 58 CEF_REQUIRE_UI_THREAD(); 59 60 AutoLock lock_scope(this); 61 62 m_Browser = browser; 63 64 } 65 66 bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser) 67 { 68 CEF_REQUIRE_UI_THREAD(); 69 70 AutoLock lock_scope(this); 71 72 73 if(m_Browser) 74 { 75 // Set a flag to indicate that the window close should be allowed. 76 m_bIsClosing = true; 77 } 78 79 return false; 80 } 81 82 void CCefBrowserEventHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) 83 { 84 CEF_REQUIRE_UI_THREAD(); 85 86 AutoLock lock_scope(this); 87 88 if(m_Browser->IsSame(browser)) 89 m_Browser = NULL; 90 }
3.在入口函数处初始化CEF
1 // Duilib_Login.cpp : 定义应用程序的入口点。 2 // 3 #include "CefBrowserApp.h" 4 #include "MainFrameWnd.h" 5 6 int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow) 7 { 8 CPaintManagerUI::SetInstance(hInstance); 9 CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("CefDemo")); 10 11 12 HRESULT Hr = ::CoInitialize(NULL); 13 if (FAILED(Hr)) return 0; 14 15 /***************************************begin初始化cef*******************************************/ 16 17 void* sandbox_info = NULL; 18 CefMainArgs main_args(hInstance); 19 CefRefPtr<CCefBrowserApp> spApp(new CCefBrowserApp); 20 21 // Execute the secondary process, if any. 22 int exit_code = CefExecuteProcess(main_args, spApp.get(),sandbox_info); 23 if (exit_code >= 0) 24 return exit_code; 25 CefSettings cSettings; 26 cSettings.no_sandbox = true; 27 cSettings.multi_threaded_message_loop = true; 28 // Execute the secondary process, if any. 29 CefInitialize(main_args, cSettings, spApp.get(),sandbox_info); 30 /***************************************结束初始化cef*******************************************/ 31 32 33 CMainFrameWnd* pMain = new CMainFrameWnd; 34 pMain->Create(NULL, _T("MainFrameWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE | WS_EX_ACCEPTFILES); 35 pMain->CenterWindow(); 36 pMain->ShowWindow(TRUE); 37 38 if (!cSettings.multi_threaded_message_loop) { 39 // Run the CEF message loop. This function will block until the application 40 // recieves a WM_QUIT message. 41 CefRunMessageLoop(); 42 } 43 else { 44 DuiLib::CPaintManagerUI::MessageLoop(); 45 } 46 47 CefShutdown(); 48 49 delete pMain; 50 ::CoUninitialize(); 51 return 0; 52 }
4.在CMainFrameWnd窗口类中定义一个Handler的成员变量
......... private: CefRefPtr<CCefBrowserEventHandler> m_handler;
在CMainFrameWnd初始化列表中构造Handler对象
CMainFrameWnd::CMainFrameWnd() :m_handler(new CCefBrowserEventHandler()) { }
5.在虚函数InitWindow()中创建CEF浏览器
void CMainFrameWnd::InitWindow() { RECT rc; ::GetClientRect(this->GetHWND(),&rc); rc.top += 28; rc.left += 1; rc.right += -1; rc.bottom += -1; CefWindowInfo info; info.SetAsChild(*this, rc); TCHAR tszModule[MAX_PATH + 1] = { 0 }; ::GetModuleFileName(NULL, tszModule, MAX_PATH); ::PathRemoveFileSpec(tszModule); wstring url =tszModule; url+=L"\\JS C++.html"; CefBrowserSettings settings1; CefBrowserHost::CreateBrowser(info, m_handler.get(), CefString ("http://www.baidu.com"), settings1, NULL); //打开百度 //CefBrowserHost::CreateBrowser(info, m_handler.get(), CefString (url), settings1, NULL); //打开自己写的html }
6.duilib窗口关闭时需要重写LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 这个虚函数,在这个虚函数中关闭CEF浏览器
LRESULT CMainFrameWnd::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_handler && !m_handler->IsClosing()) { //第一次响应WM_CLOSE消息时 CefRefPtr<CefBrowser> browser = m_handler->GetBrowser(); if (browser.get()) { // Notify the browser window that we would like to close it. This // will result in a call to ClientHandler::DoClose() if the // JavaScript 'onbeforeunload' event handler allows it. browser->GetHost()->CloseBrowser(false); // Cancel the close. return 0; } } //第二次响应WM_CLOSE消息时 ::PostQuitMessage(1L); return 0; }
7.如果想让浏览器随着窗口大小变化自适应还需要重写LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)这个虚函数
LRESULT CMainFrameWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { WindowImplBase::OnSize(uMsg,wParam,lParam,bHandled); if (m_handler != NULL){ CefRefPtr<CefBrowser> browser = m_handler->GetBrowser(); if (browser){ CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle(); RECT rt; ::GetClientRect(m_hWnd, &rt); int cx = rt.right - rt.left -2; int cy = rt.bottom - rt.top -2; ::MoveWindow(hwnd, 1, 28, cx, cy, TRUE); } } return 0; }
8.按照这个流程走下来,可以正常显示,先看一下效果图
同时看一下进程个数:
大家应该注意到上面标注红颜色的三行代码,我在刚开始嵌入时,把这三行代码忘了没写,就出现一个问题,点"X"关闭,程序正常退出了,但有个窗口进程没退出,桌面上留下一个空白窗口,资源管理器中有显示一个进程没退出。
后来反复检查,加上那三行代码后,程序正常退出了,最后看看那三行代码的意思
/// // This function should be called from the application entry point function to // execute a secondary process. It can be used to run secondary processes from // the browser client executable (default behavior) or from a separate // executable specified by the CefSettings.browser_subprocess_path value. If // called for the browser process (identified by no "type" command-line value) // it will return immediately with a value of -1. If called for a recognized // secondary process it will block until the process should exit and then return // the process exit code. The |application| parameter may be empty. The // |windows_sandbox_info| parameter is only used on Windows and may be NULL (see // cef_sandbox_win.h for details). /// /*--cef(api_hash_check,optional_param=application, optional_param=windows_sandbox_info)--*/ int CefExecuteProcess(const CefMainArgs& args, CefRefPtr<CefApp> application, void* windows_sandbox_info);
但是加载本地的html文件,就是没写那三行代码,也不出现上面的问题,感觉很奇怪
9.Debug模式和Release模式配置
首先 在bin目录下放release版的 libcef.dll
对于链接cef的lib,在Debug模式下加载Debug的libcef.lib和libcef_dll_wrapper.lib,Release加载Release的libcef.lib和ibcef_dll_wrapper.lib
#ifdef _DEBUG # ifdef _UNICODE # pragma comment(lib, "..\\Lib\\DuiLib_ud.lib") # pragma comment(lib, "..\\Lib\\Debug\\libcef.lib") # pragma comment(lib, "..\\Lib\\Debug\\libcef_dll_wrapper.lib") # else # pragma comment(lib, "..\\Lib\\DuiLib_d.lib") # endif #else # ifdef _UNICODE # pragma comment(lib, "..\\Lib\\DuiLib_u.lib") # pragma comment(lib, "..\\Lib\\Release\\libcef.lib") # pragma comment(lib, "..\\Lib\\Release\\libcef_dll_wrapper.lib") # else # pragma comment(lib, "..\\Lib\\DuiLib.lib") # endif #endif
这样配置 我们Debug调试 或者发布Release 程序都正常运行
点击下载:CEF嵌入DuilibDemo