Qt6内嵌CEF

2024-03-01 04:12
文章标签 内嵌 qt6 cef

本文主要是介绍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

这篇关于Qt6内嵌CEF的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/761179

相关文章

JSTL 函数内使用JSTL(内嵌)

JSTL函数内使用JSTL函数 ${fn:contains(rest.methods, ${pay.id})}    这是错误的,实际上内部可以省略${} 正确写法: ${fn:contains(rest.methods, pay.id)} <c:forEach items ="${pays}" var= "pay"><div class ="col-xs-3"><la

黑马JavaWeb开发笔记14——Tomcat(介绍、安装与卸载、启动与关闭)、入门程序解析(起步依赖、SpringBoot父工程、内嵌Tomcat)

文章目录 前言一、Web服务器-Tomcat1. 简介1.1服务器概述1.2 Web服务器1.3 Tomcat 2. 基本使用2.1 下载2.2 安装与卸载2.3 启动与关闭2.4 常见问题 二、入门程序解析1. 起步依赖2. SpringBoot父工程3. 内嵌Tomcat 总结 前言 本篇文章是2023年最新黑马JavaWeb开发笔记14:Tomcat(介绍、安装与卸载

Qt6+VTK9环境配置

Qt6+VTK9环境配置 说明1 Qt6安装2 VTK源码编译2.1 源码下载2.2 工程编译2.3 设置环境变量 3 Qt+VTK项目构建3.1 使用qmake管理项目3.2 使用cmake管理项目 参考资料 说明 由于想做一点新的东西,需要去探索一些工具,对于VTK之前没有了解过,在进行环境配置时,参考了其他一些博客,由于版本的问题,采了不少坑,所以,在这里做个记录整理。我所

qt6 socket 不使用代理 socket error: The proxy type is invalid for this operation

qt 5.8之后,socket默认使用代理 参考 https://www.cnblogs.com/cppskill/p/11730452.html#:~:text=%E5%9C%A8%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E9%87%8C%E5%AE%9A%E4%B9%89,Proxy%29%3B%E3%80%82 #include <QNetworkProx

cef OnBeforePopup禁止弹出新窗体

bool SimpleHandler::OnBeforePopup(   CefRefPtr<CefBrowser> browser,   CefRefPtr<CefFrame> frame,   const CefString& target_url,   const CefString& target_frame_name,   WindowOpenDisposition target_dis

Android内嵌MuPDF打开PDF文件

一、基本实现        1,导入so库;         2,声明库文件中方法 </pre><pre name="code" class="java">public class MuPDFCore {/* load our native library */static {System.loadLibrary("mupdf");}/* Readable members */pr

逆向工程核心原理 Chapter20 | “内嵌补丁”练习

前言 自己学《逆向工程核心原理》一书的记录,只记录自己觉得重要/有用的一些点。 知识点学习 很实用的一个逆向技术。 原理: “壳”的逻辑也是这样的。EP处先解密OEP代码,再跳转到洞穴代码,恢复IAT之类的,然后跳回OEP执行源程序代码。 代码补丁与内嵌补丁的区别: PatchMe练习 记得上次寒假学过一次,现在再练/学一次。 IDA看可以很清晰的看到解密逻辑。 流程:

Qt6中使用qcustomplot时报错:file too big

错误描述:在qt6中使用qcustomplot时报错提示:file too big 提示是.cpp文件太大导致的,需要在.pro文件中再增加一行 QMAKE_CXXFLAGS += "-Wa,-mbig-obj"修改编译器的设置

QtCreator错误:Qt没有被正确安装,请运行make install(适用Qt4、Qt5、Qt6)

一、问题环境 (1)Windows 10企业版,64位 (2)Visual Studio 2019 (3)Qt5.12.12 x64版本、Qt4.8.6 x64版本(自己编译) (4)Qt Creator 12.0.1 二、问题描述:         自己在编译完整Qt5.12.12源码后,想要在Qt Creator12.0.1中使用自己编译的Qt5.12.12_x64版本,进行工作;

关于C语言中内嵌汇编指令的一个小细节

今天修改u-boot时,在编译的过程中,老是提示内嵌汇编指令处有语法错误,我仔细检查一下,才发现我将汇编指令写成了: _asm_ ("####一些指令####") /* error */ asm两端的下划线应该是一边两条: __asm__("####一些指令####") /* correct */