VS2019 VC++ MFC CEF(Chrome)开发环境搭建及相关功能demo(附源码)
本文章主要介紹CEF如何作為一個(gè)控件,加在MFC的窗體中,并實(shí)現(xiàn)一些功能,如:打開指定網(wǎng)址、刷新、后退關(guān)閉子窗口或頁簽、關(guān)閉全部頁簽/子窗口和主窗體、瀏覽器界面自適應(yīng)窗口大小等等,也會交代會遇到的一些坑的處理辦法,最終會附上整個(gè)項(xiàng)目的源碼。
一、下載/準(zhǔn)備cef必須的dll和lib文件
1、下載并生成VS開發(fā)環(huán)境(詳見文章:https://blog.csdn.net/yixiao0307/article/details/119908780),不在此贅述
2、創(chuàng)建最簡單的MFC窗口項(xiàng)目(詳見文章:https://blog.csdn.net/yixiao0307/article/details/119837989)
3、在MFC項(xiàng)目源碼目錄(主窗口Dlg.app文件所在目錄),創(chuàng)建文件夾cefLib,目錄結(jié)構(gòu)如下:
其中bin和lib目錄里,都有x86/Debug 和 x86/Release,便于以后擴(kuò)展x64
將網(wǎng)上下載下來的文件(cef_binary_92.0.27+g274abcf+chromium-92.0.4515.159_windows32,本文統(tǒng)稱:cef binary文件包)中的以下文件和文件夾,
- include、libcef_dll、tests、cef_paths.gypi、cef_paths2.gypi 復(fù)制到 libCef/src
- Debug 中的文件全部復(fù)制到 libCef/bin/x86/Debug/
- Release 中的文件全部復(fù)制到 libCef/bin/x86/Release/
- Debug/cef_sandbox.lib、Debug/libcef.lib 復(fù)制到 libCef/bin/x86/Debug/
- Release/cef_sandbox.lib、Release/libcef.lib 復(fù)制到 libCef/bin/x86/Release/
- 最后,再將第1點(diǎn)中(生成VS開發(fā)環(huán)境,https://blog.csdn.net/yixiao0307/article/details/119908780)用Debug/Release環(huán)境產(chǎn)生的 libcef_dll_wrapper.lib 和 libcef_dll_wrapper.pdb ,分別放到libCef/bin/x86/Debug/ 和 libCef/bin/x86/Release/,最終這兩個(gè)目錄效果如下,
二、設(shè)置項(xiàng)目屬性(Debug/x86)
1、配置屬性 - 高級 - MFC的使用 += “在靜態(tài)庫中使用MFC”
2、配置屬性 - VC++目錄 - 包含目錄 += $(VC_SourcePath)libCEF\src
3、配置屬性 - C/C++ - 預(yù)處理器 - 預(yù)處理器定義 += _HAS_ITERATOR_DEBUGGING=0
注意:Debug環(huán)境的“預(yù)處理器定義”中,必須增加此定義語句“_HAS_ITERATOR_DEBUGGING=0”。
再注意:如果不加此預(yù)處理器定義項(xiàng),Debug編譯時(shí),會一直報(bào)錯(cuò)(要看cef的版本,有的版本不加也不會報(bào)錯(cuò))
嚴(yán)重性 代碼 說明 項(xiàng)目 文件 行 禁止顯示狀態(tài)
錯(cuò)誤 LNK2038 檢測到“_ITERATOR_DEBUG_LEVEL”的不匹配項(xiàng): 值“0”不匹配值“2”(CCefBrowserApp.obj 中) MFCCef D:\website\mfccef\MFCCef\libcef_dll_wrapper.lib(cef_logging.obj) 1
4、重點(diǎn)確認(rèn)無誤:配置屬性 - C/C++ - 代碼生成 - 運(yùn)行庫 = 多線程調(diào)試(/MTd)
5、配置屬性 - 鏈接器 - 輸入 - 附加依賴項(xiàng) +=
libCEF\lib\x86\Debug\libcef.lib
libCEF\lib\x86\Debug\libcef_dll_wrapper.lib
libCEF\lib\x86\Debug\cef_sandbox.lib
此處有些人是直接寫到主窗口Dlg.cpp文件的代碼里的,鏈接器和代碼調(diào)用只做一次就可以了,代碼如下:
6、配置屬性 - 清單工具 - 輸入和輸出 - 附加清單文件 += my.manifest
【劃重點(diǎn)】并在源碼目錄(主窗口Dlg.cpp文件所在目錄),創(chuàng)建my.manifest的文件,文件內(nèi)容如下:
【再劃重點(diǎn)】如果以上這個(gè)文件不創(chuàng)建,Debug環(huán)境運(yùn)行時(shí),會出現(xiàn)白屏的情況,這個(gè)問題困擾了我1天!
三、設(shè)置項(xiàng)目屬性(Release/x86)
1、配置屬性 - 高級 - MFC的使用 += “在靜態(tài)庫中使用MFC”
2、配置屬性 - VC++目錄 - 包含目錄 += $(VC_SourcePath)libCEF\src
4、重點(diǎn)確認(rèn)無誤:配置屬性 - C/C++ - 代碼生成 - 運(yùn)行庫 = 多線程(/MT)
5、配置屬性 - 鏈接器 - 輸入 - 附加依賴項(xiàng) +=
libCEF\lib\x86\Release\libcef.lib
libCEF\lib\x86\Release\libcef_dll_wrapper.lib
libCEF\lib\x86\Release\cef_sandbox.lib
四、創(chuàng)建 CefBrowserApp 和 CefBrowserEventHandler 類
在項(xiàng)目的頭文件目錄上,點(diǎn)擊鼠標(biāo)右鍵,執(zhí)行添加類 CCefBrowserApp
CCefBrowserApp.h
CCefBrowserApp.cpp
#include "pch.h" #include "CCefBrowserApp.h"CCefBrowserApp::CCefBrowserApp(void) {} CCefBrowserApp::~CCefBrowserApp(void) {} CefRefPtr<CefBrowserProcessHandler> CCefBrowserApp::GetBrowserProcessHandler() {return this;} void CCefBrowserApp::OnContextInitialized() {}CCefBrowserEventHandler.h
#pragma once #include "include/cef_client.h" #include <list> class CCefBrowserEventHandler:public CefClient,public CefDisplayHandler,public CefLifeSpanHandler,public CefLoadHandler { public:explicit CCefBrowserEventHandler(bool use_views); //這里的參數(shù)use_views可有可無,但需一致~CCefBrowserEventHandler();static CCefBrowserEventHandler* GetInstance();virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE { return this; }virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE { return this; }virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { return this; }void CloseAllBrowsers(bool force_close);bool IsClosing() const { return is_closing_; }bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser);virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;static bool IsChromeRuntimeEnabled(); private:const bool use_views_;typedef std::list<CefRefPtr<CefBrowser>> BrowserList;BrowserList browser_list_;bool is_closing_;//這句很重要,不寫的話需要實(shí)現(xiàn)所有虛方法,寫了就不用實(shí)現(xiàn)全部虛方法IMPLEMENT_REFCOUNTING(CCefBrowserEventHandler); };CCefBrowserEventHandler.cpp
#include "pch.h" #include "CCefBrowserEventHandler.h"#include "include/base/cef_bind.h" #include "include/cef_app.h" #include "include/cef_parser.h" #include "include/views/cef_browser_view.h" #include "include/views/cef_window.h" #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_helpers.h"CCefBrowserEventHandler* g_instance = nullptr; CCefBrowserEventHandler::CCefBrowserEventHandler(bool use_views):use_views_(use_views),is_closing_(false){DCHECK(!g_instance);g_instance = this; }CCefBrowserEventHandler::~CCefBrowserEventHandler() {g_instance = nullptr; } CCefBrowserEventHandler* CCefBrowserEventHandler::GetInstance() {return g_instance; }bool CCefBrowserEventHandler::DoClose(CefRefPtr<CefBrowser> browser) {CEF_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.is_closing_ = true;}// Allow the close. For windowed browsers this will result in the OS close// event being sent.return false; }void CCefBrowserEventHandler::CloseAllBrowsers(bool force_close) {if (!CefCurrentlyOn(TID_UI)) {// Execute on the UI thread.CefPostTask(TID_UI, base::Bind(&CCefBrowserEventHandler::CloseAllBrowsers, this, 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); }void CCefBrowserEventHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {CEF_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 CCefBrowserEventHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {CEF_REQUIRE_UI_THREAD();// Add to the list of existing browsers.browser_list_.push_back(browser); }bool CCefBrowserEventHandler::IsChromeRuntimeEnabled() {static int value = -1;if (value == -1) {CefRefPtr<CefCommandLine> command_line =CefCommandLine::GetGlobalCommandLine();value = command_line->HasSwitch("enable-chrome-runtime") ? 1 : 0;}return value == 1; }有了以上兩個(gè)類,才能在MFC項(xiàng)目中對CEF進(jìn)行初始化和調(diào)用,這兩個(gè)類我是從cef binary文件包的這兩個(gè)類里摘抄過來的。
五、初始化Cef
1、增加引用
#include "include/cef_client.h" #include "include/cef_app.h" #include "CCefBrowserApp.h"2、在項(xiàng)目主類的InitInstance()方法的頂部,增加cef初始化代碼
void* sandbox_info = NULL; CefMainArgs main_args(m_hInstance); CefRefPtr<CCefBrowserApp> app(new CCefBrowserApp);int exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info); if (exit_code >= 0) {return exit_code; } CefSettings settings; CefSettingsTraits::init(&settings); settings.no_sandbox = true; settings.multi_threaded_message_loop = true; settings.ignore_certificate_errors = true; settings.command_line_args_disabled = true; CefInitialize(main_args, settings, app.get(), sandbox_info);
3、在InitInstance()方法的底部,返回語句前,增加代碼:
六、窗體中調(diào)用Cef
1、增加引用
#include <include/internal/cef_win.h> #include <include/internal/cef_ptr.h> #include <include/cef_browser.h> #include <include/cef_app.h> #include "CCefBrowserEventHandler.h" #include "include/views/cef_browser_view.h"2、將窗體中的按鈕和字刪除,新拖入一個(gè)Picture Control控件,并分別設(shè)置屬性(選中控件,右鍵-屬性)為:
- ID = IDC_STATIC_BODY
- 類型 = Rectangle
- 可見 = False
預(yù)覽效果:
3、在主窗體的OnInitDialog()方法底部,返回語句上方,增加代碼:
七、運(yùn)行效果
看到CSDN顯示在自己做的窗口中,太漂亮了,美中不足的是,Debug中結(jié)束程序運(yùn)行后,總是會提示“未加載libcef.dll.pdb”的錯(cuò)誤(如下圖)(暫時(shí)無解),但是Release環(huán)境中一切正常。
八、功能應(yīng)用
以下功能實(shí)現(xiàn)詳見:https://blog.csdn.net/yixiao0307/article/details/119964356
1、打開指定網(wǎng)址
2、刷新
3、后退
4、調(diào)用本地Vue
5、自動登錄(自動填充賬號和密碼)
6、關(guān)閉子窗口
7、HTML/JS中關(guān)閉主窗體
8、MFC發(fā)送消息給CEF中的HTML/JS
9、瀏覽器自適應(yīng)窗體大小
九、源碼
源碼版本庫地址:https://gitee.com/kefong/mfccef
總結(jié)
以上是生活随笔為你收集整理的VS2019 VC++ MFC CEF(Chrome)开发环境搭建及相关功能demo(附源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps切图:Cutterman插件的安装和
- 下一篇: 华为FreeBuds pro评测