日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

VS2019 VC++ MFC CEF(Chrome)开发环境搭建及相关功能demo(附源码)

發(fā)布時間:2024/3/26 c/c++ 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VS2019 VC++ MFC CEF(Chrome)开发环境搭建及相关功能demo(附源码) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文章主要介紹CEF如何作為一個控件,加在MFC的窗體中,并實現(xiàn)一些功能,如:打開指定網(wǎng)址、刷新、后退關(guān)閉子窗口或頁簽、關(guān)閉全部頁簽/子窗口和主窗體、瀏覽器界面自適應(yīng)窗口大小等等,也會交代會遇到的一些坑的處理辦法,最終會附上整個項目的源碼。

一、下載/準備cef必須的dll和lib文件

1、下載并生成VS開發(fā)環(huán)境(詳見文章:https://blog.csdn.net/yixiao0307/article/details/119908780),不在此贅述
2、創(chuàng)建最簡單的MFC窗口項目(詳見文章:https://blog.csdn.net/yixiao0307/article/details/119837989)
3、在MFC項目源碼目錄(主窗口Dlg.app文件所在目錄),創(chuàng)建文件夾cefLib,目錄結(jié)構(gòu)如下:

其中bin和lib目錄里,都有x86/Debug 和 x86/Release,便于以后擴展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點中(生成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/,最終這兩個目錄效果如下,

二、設(shè)置項目屬性(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ù)處理器定義項,Debug編譯時,會一直報錯(要看cef的版本,有的版本不加也不會報錯)

嚴重性 代碼 說明 項目 文件 行 禁止顯示狀態(tài)
錯誤 LNK2038 檢測到“_ITERATOR_DEBUG_LEVEL”的不匹配項: 值“0”不匹配值“2”(CCefBrowserApp.obj 中) MFCCef D:\website\mfccef\MFCCef\libcef_dll_wrapper.lib(cef_logging.obj) 1

4、重點確認無誤:配置屬性 - C/C++ - 代碼生成 - 運行庫 = 多線程調(diào)試(/MTd)

5、配置屬性 - 鏈接器 - 輸入 - 附加依賴項 +=

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)用只做一次就可以了,代碼如下:

#ifdef _DEBUG #include "libCEF\lib\x86\Debug\libcef.lib" #include "libCEF\lib\x86\Debug\libcef_dll_wrapper.lib" #include "libCEF\lib\x86\Debug\cef_sandbox.lib" #endif

6、配置屬性 - 清單工具 - 輸入和輸出 - 附加清單文件 += my.manifest

劃重點】并在源碼目錄(主窗口Dlg.cpp文件所在目錄),創(chuàng)建my.manifest的文件,文件內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!--The ID below indicates application support for Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!-- 10.0 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> </application> </compatibility> </assembly>

【再劃重點】如果以上這個文件不創(chuàng)建,Debug環(huán)境運行時,會出現(xiàn)白屏的情況,這個問題困擾了我1天!

三、設(shè)置項目屬性(Release/x86)

1、配置屬性 - 高級 - MFC的使用 += “在靜態(tài)庫中使用MFC”

2、配置屬性 - VC++目錄 - 包含目錄 += $(VC_SourcePath)libCEF\src

4、重點確認無誤:配置屬性 - C/C++ - 代碼生成 - 運行庫 = 多線程(/MT)

5、配置屬性 - 鏈接器 - 輸入 - 附加依賴項 +=

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 類

在項目的頭文件目錄上,點擊鼠標右鍵,執(zhí)行添加類 CCefBrowserApp


CCefBrowserApp.h

#pragma once #include "include\cef_app.h" class CCefBrowserApp :public CefApp, public CefBrowserProcessHandler { public:CCefBrowserApp(void);virtual ~CCefBrowserApp(void);public:virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler();virtual void OnContextInitialized(); protected://這句很重要,不寫的話需要實現(xiàn)所有虛方法,寫了就不用實現(xiàn)全部虛方法IMPLEMENT_REFCOUNTING(CCefBrowserApp); };

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_;//這句很重要,不寫的話需要實現(xiàn)所有虛方法,寫了就不用實現(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; }

有了以上兩個類,才能在MFC項目中對CEF進行初始化和調(diào)用,這兩個類我是從cef binary文件包的這兩個類里摘抄過來的。

五、初始化Cef

1、增加引用

#include "include/cef_client.h" #include "include/cef_app.h" #include "CCefBrowserApp.h"

2、在項目主類的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()方法的底部,返回語句前,增加代碼:

//關(guān)閉CEF CefQuitMessageLoop(); CefShutdown();

六、窗體中調(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、將窗體中的按鈕和字刪除,新拖入一個Picture Control控件,并分別設(shè)置屬性(選中控件,右鍵-屬性)為:

  • ID = IDC_STATIC_BODY
  • 類型 = Rectangle
  • 可見 = False

    預(yù)覽效果:

    3、在主窗體的OnInitDialog()方法底部,返回語句上方,增加代碼:
//沒啥用抄來的 const bool use_views = true; //占位子用的控件大小描述信息(不顯示 CRect rtBody; //chrome控件信息類 CefWindowInfo cefWindowInfo;//獲取窗口占位控件的坐標和大小 GetDlgItem(IDC_STATIC_BODY)->GetWindowRect(&rtBody); //減去邊框和標題欄的寬度 RECT rcBody = { rtBody.left - 8, rtBody.top - 31, rtBody.Width(), rtBody.Height() }; //將chrome作為控件加載到MFC窗體中 cefWindowInfo.SetAsChild(GetSafeHwnd(), rcBody); CefBrowserSettings browser_settings; // CMFCCefDlg 對話框 CefRefPtr<CCefBrowserEventHandler> cef_handler; cef_handler = new CCefBrowserEventHandler(use_views); CefBrowserHost::CreateBrowser(cefWindowInfo, cef_handler, "https://blog.csdn.net", browser_settings, nullptr, nullptr);

七、運行效果


看到CSDN顯示在自己做的窗口中,太漂亮了,美中不足的是,Debug中結(jié)束程序運行后,總是會提示“未加載libcef.dll.pdb”的錯誤(如下圖)(暫時無解),但是Release環(huán)境中一切正常。

八、功能應(yīng)用

以下功能實現(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。