转载:https://xie.infoq.cn/article/1512f3ac7855295638ca51ee6(Qt下使用CMake编译CEF很关键)
转载:https://blog.csdn.net/qq_41474648/article/details/146129048
转载:https://blog.csdn.net/weixin_45551020/article/details/136383436
工作中没有小事:点石成金,滴水成河,只有认真对待自己所做的一切事情,才能克服万难,取得成功。
一、下载CEF CEF Automated Builds
我下载的是
二、使用CMake 生产CEF解决方案
不勾选画红色方框的
点击下方Generate 生成解决方案
三、编译libcef_dll_wrapper.lib
Qt 中常使用的是动态链接(即 MDd),所以需要使用 MDd 的方式重新编译 libcef_dll_wrapper.lib。
右键项目 libcef_dll_wrapper->属性->C/C++->代码生成->运行库:
改为“多线程调试 DLL (/MDd)”(如果是 release 版,则改为“多线程 DLL (/MD)”)
然后重新生成就可以了
注意: Qt Creator 创建的嵌入 cef 功能的项目,debug 运行加载的页面是空白的(有问题),所以只能创建 release 版本。
三、vs新建QtCEF的demo
- 我们先需要复制cef目录下(前面编译的cef目录)Include到demo下的目录里面
- lib目录下存放CEF程序编译时依赖的静态链接库(.lib文件)。主要有libcef.lib和libcef_dll_wrapper.lib,注意区分debug和release版本
- 链接器-》常规-》附加库目录 $(SolutionDir)\lib\Release
- 链接器-》常规-》输入:(注意区分debug和release)libcef.lib libcef_dll_wrapper.lib
- exe同级目录下的文件(注意区分debug和release
main.cpp
include "QtCEF.h" #include <QtWidgets/QApplication> #include "simple_app.h"/** * 初始化QT以及CEF相关 */ int init_qt_cef(int& argc, char** argv) {const HINSTANCE h_instance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));const CefMainArgs main_args(h_instance);const CefRefPtr<SimpleApp> app(new SimpleApp); //CefApp实现,用于处理进程相关的回调。const int exit_code = CefExecuteProcess(main_args, app.get(), nullptr);if (exit_code >= 0){return exit_code;}// 设置配置 CefSettings settings;settings.multi_threaded_message_loop = true; //多线程消息循环settings.log_severity = LOGSEVERITY_DISABLE; //日志settings.no_sandbox = true; //沙盒 CefInitialize(main_args, settings, app, nullptr);return -1; }int main(int argc, char *argv[]) {QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // 解决高DPI下,界面比例问题 QApplication a(argc, argv);const int result = init_qt_cef(argc, argv);if (result >= 0){return result;}QtCEF w;w.show();int ret = a.exec();CefShutdown(); // 关闭CEF,释放资源return ret; }
QtCEF.h
#include <QtWidgets/QMainWindow> #include "ui_QtCEF.h" #include "simple_handler.h"class QtCEF : public QMainWindow {Q_OBJECTpublic:QtCEF(QWidget *parent = Q_NULLPTR);private:Ui::QtCEFClass ui;private:CefRefPtr<SimpleHandler> m_handler; };
QtCEF.cpp
#include "QtCEF.h" #include "include/cef_request_context.h"QtCEF::QtCEF(QWidget *parent): QMainWindow(parent), m_handler(new SimpleHandler()) {ui.setupUi(this);CefWindowInfo cef_wnd_info;QString str_url = "https://www.baidu.com/";RECT win_rect;QRect rect = this->geometry();win_rect.left = rect.left();win_rect.right = rect.right();win_rect.top = rect.top();win_rect.bottom = rect.bottom();cef_wnd_info.SetAsChild((HWND)this->winId(), win_rect); //将cef界面嵌入qt界面中 CefBrowserSettings cef_browser_settings;CefBrowserHost::CreateBrowser(cef_wnd_info,m_handler,str_url.toStdString(),cef_browser_settings,nullptr, CefRequestContext::GetGlobalContext()); }
simple_handler.h
#include "include/cef_client.h"#include <list>class SimpleHandler : public CefClient,public CefLifeSpanHandler,public CefLoadHandler { public:explicit SimpleHandler();~SimpleHandler();// Provide access to the single global instance of this object.static SimpleHandler* GetInstance();virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE{return this;}virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { return this; }// CefLifeSpanHandler methods:virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;// CefLoadHandler methods:virtual void OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString& errorText,const CefString& failedUrl) OVERRIDE;// Request that all existing browser windows close.void CloseAllBrowsers(bool force_close);bool IsClosing() const { return is_closing_; }private:// List of existing browser windows. Only accessed on the CEF UI thread.typedef std::list<CefRefPtr<CefBrowser>> BrowserList;BrowserList browser_list_;bool is_closing_;// Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleHandler); };
simple_handler.cpp
#include "simple_handler.h"#include <sstream> #include <string>#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"namespace {SimpleHandler* g_instance = nullptr;// Returns a data: URI with the specified contents.std::string GetDataURI(const std::string& data, const std::string& mime_type){return "data:" + mime_type + ";base64," +CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString();} } // namespace SimpleHandler::SimpleHandler() : is_closing_(false) {DCHECK(!g_instance);g_instance = this; }SimpleHandler::~SimpleHandler() {g_instance = nullptr; }// static SimpleHandler* SimpleHandler::GetInstance() {return g_instance; }void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {CEF_REQUIRE_UI_THREAD();// Add to the list of existing browsers. browser_list_.push_back(browser); }bool SimpleHandler::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 SimpleHandler::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 SimpleHandler::OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString& errorText,const CefString& failedUrl) {CEF_REQUIRE_UI_THREAD();// Don't display an error for downloaded files.if (errorCode == ERR_ABORTED)return;// Display a load error message using a data: URI. std::stringstream ss;ss << "<html><body bgcolor=\"white\">""<h2>Failed to load URL "<< std::string(failedUrl) << " with error " << std::string(errorText)<< " (" << errorCode << ").</h2></body></html>";frame->LoadURL(GetDataURI(ss.str(), "text/html")); }void SimpleHandler::CloseAllBrowsers(bool force_close) {if (!CefCurrentlyOn(TID_UI)){// Execute on the UI thread.CefPostTask(TID_UI, base::Bind(&SimpleHandler::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); }
simple_app.h
#include "include/cef_app.h"// Implement application-level callbacks for the browser process. class SimpleApp : public CefApp, public CefBrowserProcessHandler { public:SimpleApp();// CefApp methods:virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()OVERRIDE{return this;}// CefBrowserProcessHandler methods:virtual void OnContextInitialized() OVERRIDE;private:// Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleApp); };
simple_app.cpp
#include "simple_app.h"#include <string> #include "include/views/cef_window.h" #include "include/wrapper/cef_helpers.h" #include "simple_handler.h"SimpleApp::SimpleApp() { }void SimpleApp::OnContextInitialized() {CEF_REQUIRE_UI_THREAD(); }