日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

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

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

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

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

其中bin和lib目錄里,都有x86/Debug 和 x86/Release,便于以后擴展x64

將網上下載下來的文件(cef_binary_92.0.27+g274abcf+chromium-92.0.4515.159_windows32,本文統稱:cef binary文件包)中的以下文件和文件夾,

  • include、libcef_dll、tests、cef_paths.gypi、cef_paths2.gypi 復制到 libCef/src
  • Debug 中的文件全部復制到 libCef/bin/x86/Debug/
  • Release 中的文件全部復制到 libCef/bin/x86/Release/
  • Debug/cef_sandbox.lib、Debug/libcef.lib 復制到 libCef/bin/x86/Debug/
  • Release/cef_sandbox.lib、Release/libcef.lib 復制到 libCef/bin/x86/Release/
  • 最后,再將第1點中(生成VS開發環境,https://blog.csdn.net/yixiao0307/article/details/119908780)用Debug/Release環境產生的 libcef_dll_wrapper.lib 和 libcef_dll_wrapper.pdb ,分別放到libCef/bin/x86/Debug/libCef/bin/x86/Release/,最終這兩個目錄效果如下,

二、設置項目屬性(Debug/x86)

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

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

3、配置屬性 - C/C++ - 預處理器 - 預處理器定義 += _HAS_ITERATOR_DEBUGGING=0
注意:Debug環境的“預處理器定義”中,必須增加此定義語句“_HAS_ITERATOR_DEBUGGING=0”。

再注意:如果不加此預處理器定義項,Debug編譯時,會一直報錯(要看cef的版本,有的版本不加也不會報錯)

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

4、重點確認無誤:配置屬性 - C/C++ - 代碼生成 - 運行庫 = 多線程調試(/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文件的代碼里的,鏈接器和代碼調用只做一次就可以了,代碼如下:

#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文件所在目錄),創建my.manifest的文件,文件內容如下:

<?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>

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

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

1、配置屬性 - 高級 - MFC的使用 += “在靜態庫中使用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

四、創建 CefBrowserApp 和 CefBrowserEventHandler 類

在項目的頭文件目錄上,點擊鼠標右鍵,執行添加類 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://這句很重要,不寫的話需要實現所有虛方法,寫了就不用實現全部虛方法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); //這里的參數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_;//這句很重要,不寫的話需要實現所有虛方法,寫了就不用實現全部虛方法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進行初始化和調用,這兩個類我是從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()方法的底部,返回語句前,增加代碼:

//關閉CEF CefQuitMessageLoop(); CefShutdown();

六、窗體中調用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控件,并分別設置屬性(選中控件,右鍵-屬性)為:

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

    預覽效果:

    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中結束程序運行后,總是會提示“未加載libcef.dll.pdb”的錯誤(如下圖)(暫時無解),但是Release環境中一切正常。

八、功能應用

以下功能實現詳見:https://blog.csdn.net/yixiao0307/article/details/119964356
1、打開指定網址
2、刷新
3、后退
4、調用本地Vue
5、自動登錄(自動填充賬號和密碼)
6、關閉子窗口
7、HTML/JS中關閉主窗體
8、MFC發送消息給CEF中的HTML/JS
9、瀏覽器自適應窗體大小

九、源碼

源碼版本庫地址:https://gitee.com/kefong/mfccef

總結

以上是生活随笔為你收集整理的VS2019 VC++ MFC CEF(Chrome)开发环境搭建及相关功能demo(附源码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。