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.mzph.cn/news/709937.shtml

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

相关文章

thefour--Love is like a tide

最后一部分了&#xff0c;要开始进行我们的训练了。 先上代码&#xff1a; import os import numpy as np from tqdm import tqdm import tensorflow as tf from thetwo import NeuralStyleTransferModel import theone import thethree #创建模型 modelNeuralStyleTransferM…

代码随想录训练营第31天 | 理论基础、LeetCode 455.分发饼干、

目录 理论基础 视频讲解&#xff1a;手把手带你学会操作链表 | 贪心算法理论基础&#xff01;_哔哩哔哩_bilibili LeetCode 455.分发饼干 文章讲解&#xff1a;代码随想录(programmercarl.com) 视频讲解&#xff1a;贪心算法&#xff0c;你想先喂哪个小孩&#xff1f;| Le…

【GameFramework框架内置模块】7、事件(Event)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录&#xff1a; https://blog.csdn.net/q7…

【Vue】路由

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue ⛺️稳中求进&#xff0c;晒太阳 目录 路由 单页应用程序 总结&#xff1a; VueRouter 核心步骤&#xff1a; 组件存放目录的问题 路由的封装 声明式导航 声明式导航 - 导航链…

Go语言必知必会100问题-11 使用选项模式

使用选项模式 在设计API时&#xff0c;可能会遇到一个问题&#xff1a;如何处理可选配置&#xff1f;有效的解决可选配置问题可以提高API的灵活性。本文通过一个具体示例说明处理可选配置的一些方法。该示例的要求是设计一个对外提供创建HTTP服务器的库函数。函数定义如下&…

服了,阿里云服务器和腾讯云服务器价格差不多怎么选择?

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器62元一年&#xff0c;2核2G3M、2核4G、4核8G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配置价格表…

高级语言期末2011级B卷(计算机学院)

1.编写函数&#xff0c;实现按照如下公式计算的功能&#xff0c;其中n为自然数 #include <stdio.h>int fac(int n) {if(n0)return 1;elsereturn n*fac(n-1); }float fun(int n) {float flag;float sum0;for(int i0; i<n; i) {flagi/((i1)*fac(i2));sumflag;}return su…

重推请求之curl和fiddler

在实际的项目中会有出现问题&#xff0c;想重现的场景&#xff0c;比较重新调用一个服务&#xff0c;那么如何进行快速的重推请求呢&#xff0c;记录下来&#xff0c;方便备查。 主要有curl和fiddler两种方式&#xff0c;下面详细说。 方式一、curl 命令 curl 是一个利用URL规…

云上攻防-云服务篇弹性计算服务器云数据库实例元数据控制角色AK控制台接管

知识点: 1、云服务-弹性计算服务器-元数据&SSRF&AK 2、云服务-云数据库-外部连接&权限提升 章节点&#xff1a; 云场景攻防&#xff1a;公有云&#xff0c;私有云&#xff0c;混合云&#xff0c;虚拟化集群&#xff0c;云桌面等 云厂商攻防&#xff1a;阿里云&am…

租赁小程序|租赁系统|租赁软件开发带来高效运营

随着社会的不断发展和科技的不断进步&#xff0c;越来越多的企业开始关注设备租赁业务。设备租赁作为一种短期使用设备的方式&#xff0c;为企业提供了灵活和成本节约的优势。针对设备租赁业务的管理和提升企业竞争力的需求&#xff0c;很多企业选择定制开发设备租赁系统。本文…

js 面试 1判断变量是否是数组 2 检测数据类型方法

1 是否是数组 1) typeof 检测数据类型运算符 优点&#xff1a;使用简单 缺点&#xff1a;只能检测基本类型&#xff08;除null外&#xff09; console.log(typeof(10)) //Number console.log(typeof(false)) //boolean console.log(typeof(hello)) //string console.log(typeof…

vue使用gitshot生成gif

vue使用gitshot生成gif 问题背景 本文将介绍vue中使用gitshot生成gif。 问题分析 解决思路&#xff1a; 使用input组件上传一个视频&#xff0c;获取视频文件后用一个video组件进行播放&#xff0c;播放过程进行截图生成图片数组。 demo演示上传一个视频&#xff0c;然后生…

如何使用Docker部署IT-Tools并结合内网穿透实现公网访问本地工具箱服务

作为程序员&#xff0c;在日常工作中&#xff0c;需要借助一些工具来提高我们工作效率&#xff0c;IT-Tools是为开发人员度身打造的一套便捷在线工具。它提供全面功能&#xff0c;使开发者能以更高效方式完成任务。经由IT-Tools&#xff0c;开发人员能轻松应对各类技术挑战&…

C++之数组

1&#xff0c;概述 所谓数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 特点1&#xff1a;数组中没干过数据元素都是相同的数据类型 特点2&#xff1a;数组都是连续存放位置组成的 2&#xff0c;一维数组 2.1 一维数组的定义 一维数组定义有三种…

Leetcode583. 两个字符串的删除操作 -代码随想录

题目&#xff1a; 代码(首刷自解 2024年2月29日&#xff09;&#xff1a; class Solution { public:// 动态规划 好像和找最长公共子序列一样&#xff1f;int minDistance(string word1, string word2) {int sz1 word1.size();int sz2 word2.size();// dp initvector<vec…

SD-WAN技术:优化国内外服务器访问的关键

在全球化的商业环境中&#xff0c;企业经常需要在国内访问国外的服务器。然而&#xff0c;由于地理位置和网络架构的限制&#xff0c;这种跨国访问往往会遇到速度慢、延迟高等问题。SD-WAN&#xff08;软件定义广域网&#xff09;技术的兴起&#xff0c;为企业提供了一种新的解…

八股文打卡day24——数据库(1)

面试题&#xff1a;左连接和右连接的区别&#xff1f; 我的回答&#xff1a; 左连接的SQL语句是&#xff1a;左表 left join 右表 on 连接条件&#xff0c;表示以左表为基础&#xff0c;将左表的的所有记录与右表进行连接。即使右表中没有与左表匹配的记录&#xff0c;左连接…

Linux-Uboot命令

help命令 进入 uboot 的命令行模式后输入“help”或者“&#xff1f;”&#xff0c;然后按下回车即可查看当前 uboot 所支持的命令。 查看某一个命令的帮助信息&#xff1a;&#xff1f;命令名称 或 help命令名称 信息查询命令 常用的和信息查询有关的命令有 3 个…

Cookie、Session和JWT

摘要&#xff1a;Cookie、Session和JWT都不是什么新的技术了&#xff0c;最近用到了就比较和总结下。 我们知道http协议是无状态的&#xff0c;用户登录后如何验证和保存用户状态呢&#xff1f;下面来介绍 1. 使用Cookie和Session验证登录状态 session是保存在服务端的一种数…

STM32串口通信(发送与接收数据)

文章目录 前言一、介绍部分通信接口术语解释 串口通信简介硬件电路电平标准串口参数串口时序USART简介USART框图USRAT基本结构数据帧起始位检测波特率发生器CH340G 二、实例部分使用串口发送数据接线图代码实现重定向printf需要勾上Use MicroLIB中文不乱码方法 串口的发送与接收…