Qt6内嵌CEF

一、下载CEF

  1. CEF下载地址:https://cef-builds.spotifycdn.com/index.html
    或https://bitbucket.org/chromiumembedded/cef/src/master/

  2. 选择对应系统的版本(本教程选择的是116.0.19)
    在这里插入图片描述

  3. CMake下载地址:https://cmake.org/download/

    1. 注意CEF版本,CEF116.0.19的需要cmake3.21以上版本才支持(本教程选择的是3.27.4)

二、CMake编译CEF源码

1、cmake源码

在这里插入图片描述在这里插入图片描述在这里插入图片描述
注意:低版本需要取消勾选USE_SENDBOX,否则会报错(如:vs17+CEF_92.0.26+cmake3.20.6),vs17支持的最高版本应该就到92了,有兴趣的可以每个版本都测一下

2、文件内容介绍

在这里插入图片描述

  • ALL_BUILD:是cmake自动生成的辅助工程。
  • cef_gtest:包含ceftests目标使用的Google C++测试框架。
  • ceftests:包含执行CEF API的单元测试。
  • cefclient:一个包含CEF各种API演示的浏览器程序Demo。
  • cefsimple:一个创建CEF浏览器程序所需最少功能的Demo。
  • libcef_dll_wrapper:对cef库的C++代码封装库。
  • ALL_BUILD与ZERO_CHECK:是cmake自动生成的辅助工程。

三、运行示例

在这里插入图片描述在这里插入图片描述

四、生成动态链接库

  1. 右键项目 libcef_dll_wrapper->属性->C/C+±>代码生成->运行库:改为“多线程调试 DLL (/MDd)”(如果是 release 版,则改为“多线程 DLL (/MD)”)

五、vs版本与cef版本

六、使用vs2022执行CMakeLists.txt

七、qt工程集成CEF

  1. 介绍

    1. CEF是多进程的,浏览器在运行时会在window系统中创建多个进程,并且每个进程都是以命令行形式启动。CEF通过命令行启动进程,主要包含《浏览器进程》和《渲染进程》,一个进程程序启动后,通过CefApp接口将逻辑功能“注入”到CEF框架
      在这里插入图片描述

    2. CEF函数介绍

      1. CEF框架通过回调函数GetBrowserProcessHandler() 获取程序对象。
      2. OnContextInitialized()函数初始化浏览器,并最后创建出一个浏览器窗口。
      3. CefBrowserHost::CreateBrowser()函数需要一个CefClient对象(需要自己继承重写),该对象内包含了CEF框架的handle,例:
        1. CefContextMenuHandler,主要用于处理 Context Menu 事件。

        2. CefDialogHandler,主要用来处理对话框事件。

        3. CefDisplayHandler,处理与页面状态相关的事件,如页面加载情况的变化,地址栏变化,标题变化等事件。

        4. GetDragHandler,处理拖拽相关的事件,如从外边拖入浏览器事件
          CefDownloadHandler,主要用来处理文件下载。

        5. CefFocusHandler,主要用来处理焦点事件。

        6. CefGeolocationHandler,用于申请 geolocation 权限。

        7. CefJSDialogHandler,主要用来处理 JS 对话框事件。

        8. CefKeyboardHandler,主要用来处理键盘输入事件。

        9. CefLifeSpanHandler,主要用来处理与浏览器生命周期相关的事件,与浏览器对象的创建、销毁以及弹出框的管理。

          1. OnBeforePopup 方法控制弹出窗口的内容,位置等等。
        10. CefLoadHandler,主要用来处理浏览器页面加载状态的变化,如页面加载开始,完成,出错等。

        11. CefRenderHandler,主要用来处在在窗口渲染功能被关闭的情况下的事件。

        12. CefRequestHandler,主要用来处理与浏览器请求相关的的事件,如资源的的加载,重定向等

  2. 集成流程

    1. 创建带有界面的qt工程。

    2. 在解决方案同级目录下新建CEF文件夹用于存放工程依赖文件

      1. 目录结构

        • CEF/bin
          该目录下存放CEF程序运行时所需要的所有动态库(.dll文件)。区分debug和release版本,从CEF二进制发行包根目录下拷贝过来,程序运行时需要将该目录下所有文件拷贝到exe同级目录下。
        • CEF/include
          该目录下存放CEF程序的头文件,从CEF二进制发行包根目录下拷贝过来。
        • CEF/lib
          该目录下存放CEF程序编译时依赖的静态链接库(.lib文件)。主要有libcef.lib和libcef_dll_wrapper.lib,注意区分debug和release版本。
        • CEF/resources
          该目录下存放CEF程序运行时所需要的资源文件,程序运行时需要将该目录下所有文件拷贝到exe同级目录下。
    3. 简单集成

      1. 参考test/cefsimple工程,现阶段使用的仍然是CEF本身的消息循环和显示窗口。

      2. 在工程同级目录下新建cefsimple文件夹,并从test/cefsimple工程目录下拷贝以下文件,并添加到工程:

        • simple_app.cc
        • simple_app.h
        • simple_handler.cc
        • simple_handler.h
        • simple_handler_win.cc
      3. 属性配置

        1. C/C++ -》常规-》附加包含目录:$(SolutionDir)CEF

        2. C/C++ -》预处理器,添加以下宏(注意区分debug和release)

          %(PreprocessorDefinitions)
          WIN32
          _WINDOWS
          __STDC_CONSTANT_MACROS
          __STDC_FORMAT_MACROS
          _WIN32
          UNICODE
          _UNICODE
          WINVER=0x0A00
          _WIN32_WINNT=0x0A00
          NTDDI_VERSION=NTDDI_WIN10_FE
          NOMINMAX
          WIN32_LEAN_AND_MEAN
          _HAS_EXCEPTIONS=0
          PSAPI_VERSION=1
          CEF_USE_SANDBOX
          CEF_USE_ATL
          _HAS_ITERATOR_DEBUGGING=0
          CMAKE_INTDIR="Debug"
          
        3. 链接器-》常规-》附加库目录:$(SolutionDir)CEF\lib$(Configuration)

        4. 链接器-》常规-》输入:(注意区分debug和release)

          libcef.lib
          libcef_dll_wrapper.lib
          
        5. 在SimpleHandler类中重写OnBeforePopup方法,否则每次点击链接都会在新的窗口中弹出。

        6. main函数

          #include "WebAPP.h"
          #include <QtWidgets/QApplication>#include "include/cef_command_line.h"
          //#include "include/cef_sandbox_win.h"//暂时没有用到#include "cefsimple/simple_app.h"int main(int argc, char *argv[])
          {//暂时先注释掉,使用CEF窗口//QApplication a(argc, argv);//WebAPP w;//w.show();//1、获取HINSTANCEHINSTANCE hInstance = GetModuleHandle(NULL);//2、CEF命令行参数CefMainArgs main_args(hInstance);/* 3、*   CefExecuteProcess函数创建进程,首次启动会创建主进程并返回负数*   当创建子进程时会再次调用该程序,并传入参数,例:“--type=renderer”,此时返回一个大于0的值并退出不再向下执行*/int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);if (exit_code >= 0){return exit_code;}//4、CEF全局配置CefSettings settings;settings.no_sandbox = true;//5、创建一个应用实例CefRefPtr<SimpleApp> app(new SimpleApp);//6、初始化CEFCefInitialize(main_args, settings, app.get(), nullptr);//7、CEF消息循环CefRunMessageLoop();//8、关闭CefShutdown();return 1;// a.exec();
          }
    4. qt工程集成

      1. 修改SimpleAPP类,集成自QOjbect,在OnContextInitialized()函数中添加创建窗口的信号。

        #ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
        #define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_#include <QObject>
        #include "include/cef_app.h"// Implement application-level callbacks for the browser process.
        class SimpleApp : public QObject, public CefApp, public CefBrowserProcessHandler {Q_OBJECTpublic:SimpleApp();// CefApp methods:CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override {return this;}// CefBrowserProcessHandler methods:void OnContextInitialized() override;CefRefPtr<CefClient> GetDefaultClient() override;signals:void sigCefInitialized();private:// Include the default reference counting implementation.IMPLEMENT_REFCOUNTING(SimpleApp);
        };#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_//cpp
        void SimpleApp::OnContextInitialized() {CEF_REQUIRE_UI_THREAD();//用触发信号的方式创建窗口emit sigCefInitialized();}
        
      2. 创建带UI的qt类WebAPP

        1. WebAPP.h

          #pragma once#include <QtWidgets/QMainWindow>
          #include "ui_WebAPP.h"#include "cefsimple/simple_app.h"
          #include "cefsimple/simple_handler.h"class WebAPP : public QMainWindow
          {Q_OBJECTpublic:WebAPP(QWidget *parent = nullptr);WebAPP(SimpleApp* app);~WebAPP();void setSimpleApp(SimpleApp* app);private slots:void slotCreateBrowserWindow();protected:void resizeEvent(QResizeEvent* event);private:Ui::WebAPPClass ui;SimpleApp* m_simpleApp = nullptr;
          };
          
        2. WebAPP.cpp

          #include "WebAPP.h"#include "cefsimple/simple_handler.h"WebAPP::WebAPP(QWidget *parent): QMainWindow(parent)
          {ui.setupUi(this);
          }WebAPP::WebAPP(SimpleApp* app): m_simpleApp(app)
          {}WebAPP::~WebAPP(){}void WebAPP::setSimpleApp(SimpleApp* app)
          {m_simpleApp = app;bool ret = QObject::connect(m_simpleApp, &SimpleApp::sigCefInitialized, this, &WebAPP::slotCreateBrowserWindow);
          }void WebAPP::resizeEvent(QResizeEvent* event)
          {if (SimpleHandler::GetInstance()){HWND wnd = SimpleHandler::GetInstance()->getBrowserWindowHandle();if (wnd){QRect qRect = this->centralWidget()->rect();::MoveWindow(wnd, qRect.x(), qRect.y(), qRect.width(), qRect.height(), 1);}}
          }void WebAPP::slotCreateBrowserWindow()
          {CefRefPtr<SimpleHandler> handler(new SimpleHandler(false));//浏览器配置CefBrowserSettings browser_settings;//打开的网址std::string url = "https://www.baidu.com";//浏览器窗口信息CefWindowInfo windowInfo;//windowInfo.SetAsPopup(NULL, "cefsimple");//获取嵌入窗口的句柄QString name = this->objectName();QObjectList objList = this->children();QWidget* centralWidget = this->centralWidget();HWND hwnd = (HWND)(this->centralWidget()->winId());CefWindowInfo c;RECT winRect;QRect rect = this->rect();CefRect cefRect;cefRect.x = rect.x();cefRect.y = rect.y();cefRect.width = rect.width();cefRect.height = rect.height();windowInfo.SetAsChild(hwnd, cefRect);//创建浏览器窗口CefBrowserHost::CreateBrowser(windowInfo, handler, url, browser_settings, nullptr, nullptr);}
      3. main.cpp

            //1、获取HINSTANCEHINSTANCE hInstance = GetModuleHandle(NULL);//2、CEF命令行参数CefMainArgs main_args(hInstance);/* 3、*   CefExecuteProcess函数创建进程,首次启动会创建主进程并返回负数*   当创建子进程时会再次调用该程序,并传入参数,例:“--type=renderer”,此时返回一个大于0的值并退出不再向下执行*/int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);if (exit_code >= 0){return exit_code;}//4、CEF全局配置CefSettings settings;settings.no_sandbox = true;settings.multi_threaded_message_loop = true;//将CEF放在单独的线程上运行,而不是主线程//5、创建一个应用实例//CefRefPtr<SimpleApp> simpleApp(new SimpleApp);SimpleApp* simpleApp = new SimpleApp;QApplication a(argc, argv);//WebAPP w(simpleApp);//直接传入simleapp会导致webapp初始化失败WebAPP w;w.setSimpleApp(simpleApp);w.show();//6、初始化CEFCefRefPtr<SimpleApp> simpleApp2(simpleApp);CefInitialize(main_args, settings, simpleApp2.get(), nullptr);int ret = a.exec();//7、关闭//CefQuitMessageLoop();CefShutdown();return ret;
        
  3. 错误问题

    1. 错误:[0917/232542.473:FATAL:shutdown_checker.cc(30)] Check failed: !IsCefShutdown(). Object reference incorrectly held at CefShutdown

      1. debug模式下关闭程序报错,release正常,因为对象没有正确引用,退出时资源没有正确释放。
      2. 网页在退出的时候JavaScript可能还在执行,导致调用销毁顺序不一致。
      3. 注释掉SimpleHandler::OnBeforeClose函数内的//CefQuitMessageLoop();
      4. 参考博客:https://blog.csdn.net/Mingyueruya/article/details/122460285
    2. 错误:文件包含在偏移 0x120 处开始的字符,该字符在当前源字符集中无效(代码页 65001)。

      1. vs添加:工具-》自定义-》命令-》菜单栏(选择文件)-》添加命令-》文件-》高级保存选项

      2. 文件-》高级保存选项-》修改文件编码格式,重新编译工程(依赖库也需要对应)。

    3. 错误:MSB8066 。。。。。自定义生成已退出,代码1。(报错在Microsoft.CppCommon.targets文件内)

      1. 由于工程中的文件编码格式由gb2312改为了utf-8导致(具体情况具体分析),修改编码保存重新生成,可能会提示没有权限保存(因为vs安装在C盘),可以保存到其他盘再以管理员替换vs安装目录下的该文件。

CEF集成参考博客:https://blog.csdn.net/paopao_wu/category_11518677.html?spm=1001.2014.3001.5482

65001)。
1. vs添加:工具-》自定义-》命令-》菜单栏(选择文件)-》添加命令-》文件-》高级保存选项

  2. 文件-》高级保存选项-》修改文件编码格式,重新编译工程(依赖库也需要对应)。
  1. 错误:MSB8066 。。。。。自定义生成已退出,代码1。(报错在Microsoft.CppCommon.targets文件内)

    1. 由于工程中的文件编码格式由gb2312改为了utf-8导致(具体情况具体分析),修改编码保存重新生成,可能会提示没有权限保存(因为vs安装在C盘),可以保存到其他盘再以管理员替换vs安装目录下的该文件。

CEF集成参考博客:https://blog.csdn.net/paopao_wu/category_11518677.html?spm=1001.2014.3001.5482

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/501179.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql注入过waf的小姿势

小白我啊最近也是看了很多大佬的文章和视频学到了很多姿势欢迎加qq一起学习3661629617 由于这里没有现成的例子用靶场来演示 1.%00绕过 %00解码后是一个空字节将空字节放在参数后面就可以达到绕过效果 因为很多waf检测到这里就结束了 类似这样 2.脏数据绕过 可以随便定义一个…

智能家居控制系统(51单片机)

smart_home_control_system 51单片机课设&#xff0c;智能家居控制系统 使用及转载请标明出处&#xff08;最好点个赞及star哈哈&#xff09; Github地址&#xff0c;带有PPT及流程图 Gitee码云地址&#xff0c;带有PPT及流程图 ​ 以STC89C52为主控芯片&#xff0c;以矩阵键…

喜讯!持安科技CEO何艺获评安全419《2023年度十大优秀创业者》

近日&#xff0c;由网络安全产业资讯媒体安全419主办的《年度策划》2023年度十大优秀创业者正式出炉&#xff0c;零信任办公安全技术创新企业持安科技创始人兼CEO何艺&#xff0c;获评十大优秀创业者。 这是安全419第二届推出该项目的评选活动&#xff0c;安全419编辑老师在多年…

Java学习27--IDEA常用快捷键

智能显示相关提示&#xff1a;altenter,用来快速生成Scanner&#xff0c;或者new object等等&#xff0c;也可以爆红线求提示 代码模板大全ctrlj 可以快速生成try catch finally模块的surround with&#xff1a;ctrlaltt(我换成了altc) 生成getter/setter/构造器等结构-genera…

C语言可以干些什么?C语言主要涉及哪些IT领域?

C语言可以干些什么&#xff1f;C语言主要涉及哪些IT领域&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家…

【计算机图形学】Where2Act: From Pixels to Actions for Articulated 3D Objects

文章目录 1.论文做了件什么事儿2. 论文为什么要做这件事3. 介绍Introduction4. 相关工作预测语义表达推理几何和物体属性从被动观察中学习Affordance从交互中学习感知 5. 问题陈述6. 方法6.1 网络模块主干特征提取器可运动性评分模块运动建议模块运动评分模块 6.2 训练数据收集…

德人合科技 | —数据泄露可能会对公司造成哪些影响?

数据泄露可能会对公司造成多方面的影响&#xff0c;以下是一些可能的影响&#xff1a; 财务损失&#xff1a;数据泄露可能导致公司遭受财务损失。攻击者可能会盗取公司的敏感信息&#xff0c;如客户信息、银行账户信息、商业机密等&#xff0c;并利用这些信息进行欺诈、盗窃等非…

网络安全概述(一)

目录 资产保护 资产的类型 资产损失类型 资产保护考虑因素 安全强度、安全代价和侵入可能性的关系 信息安全技术发展 单机系统的信息保密阶段 信息保障阶段 信息保障技术框架IATF PDRR模型 网络攻击类型 阻断攻击、截取攻击、篡改攻击、伪造攻击 被动攻击和主动攻…

使用 WordPress SureMembers 创建 Patreon 等粉丝网站

各行各业的创意专业人士和爱好者越来越多地转向在线平台分享他们的作品、建立忠实的粉丝并创造收入。 无论您是新晋艺术家还是知名影响者&#xff0c;拥有粉丝订阅网站都可以帮助您将热情货币化&#xff0c;同时培养紧密的支持者社区。 根据Statista的一份报告&#xff0c;到…

java 商机管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 商机管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

GPT-SoVITS音色克隆-模型训练步骤

GPT-SoVITS音色克隆-模型训练步骤 GPT-SoVITS模型源码一个简单的TTS后端项目 基于模型部署和训练教程&#xff0c;语雀 模型部署和训练教程 启动模型训练的主页面 1. 切到模型路径 /psycheEpic/GPT-SoVITS进入Python虚拟环境&#xff0c;并挂起执行python脚本 conda activ…

亚信安慧AntDB:打破数据孤岛,实现实时处理

AntDB数据库以其独特的创新能力在分布式数据库领域引领潮流。其中&#xff0c;融合统一与实时处理是其两大核心创新能力&#xff0c;为其赢得广泛关注与赞誉。融合统一意味着AntDB能够将多种不同类型的数据库融合为一体&#xff0c;实现数据的统一管理与处理&#xff0c;极大地…