比QT更高效的一款开源嵌入式图形工具EGT-Ensemble Graphics Toolkit

文章目录

    • EGT-Ensemble Graphics Toolkit介绍
    • EGT具备非常高的图形渲染效率
      • EGT采用了非常优秀的开源2D图形处理引擎-Cairo
      • 开源2D图形处理引擎Cairo的优势
      • Cairo 2D图像引擎的性能
      • Cairo 2D图像引擎的实际应用案例
      • 彩蛋 - 开源EDA软件KiCAD也在使用Cairo
    • EGT高效的秘诀还有哪些
      • Cairo需要依赖Pixman
      • Pixman针对不同平台有优化
    • EGT vs QT5实际效果PK
    • 代码贴图

很多介绍资料直接来自豆包,仅代表个人意见和理解,不喜勿喷

  • EGT-Ensemble Graphics Toolkit

EGT-Ensemble Graphics Toolkit介绍

The Ensemble Graphics Toolkit (EGT)是MIcrochip针对旗下ARM9、SAMA5处理器推出来的一款运行于嵌入式Linux的C++ GUI开发工具套件。EGT(嵌入式图形工具包)提供了现代化的图形用户界面(GUI)功能、外观样式,并在嵌入式 Linux 应用中尽可能贴近底层硬件的同时最大限度地提升性能。关键词是开源、免费商用

官方介绍可以点击这里
官方给出的EGT组件依赖框图

EGT具备非常高的图形渲染效率

EGT采用了非常优秀的开源2D图形处理引擎-Cairo

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

开源2D图形处理引擎Cairo的优势

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

Cairo 2D图像引擎的性能

在这里插入图片描述

Cairo 2D图像引擎的实际应用案例

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

彩蛋 - 开源EDA软件KiCAD也在使用Cairo

在这里插入图片描述

EGT高效的秘诀还有哪些

Cairo使用Pixman来加速底层像素的操作,Pixman能够提供图像的合成、alpha 通道处理、色彩空间转换等基本的像素级别的操作

Cairo需要依赖Pixman

在这里插入图片描述

Pixman针对不同平台有优化

Pixman针对ARM SIMD架构、带NEON或者MIPS、X86等架构,都有专门针对性的优化代码,来尽可能利用处理器硬件特性,加速像素的处理速度在这里插入图片描述

EGT vs QT5实际效果PK

在Microchip SAMA5D27开发板上,跑Microchip EGT提供的潜水员例程,该例程会有潜水员的动态图片,同时也有2条鱼在界面上从左到右在游动,另外还不断有泡泡从海底喷出。同时将该例程功能移植到QT5上,然后两者在实际硬件上运行,对比CPU占用率的差异
在这里插入图片描述
视频对比
基于EGT开发的demo,全程CPU占用率在22%左右,而QT5基本都在60%以上

代码贴图

个人对QT开发不是很熟悉,欢迎提出更好的优化方案
以下是QT5

#include <QApplication>
#include <QPainter>
#include <QTimer>
#include <QTime>
#include <QLabel>
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , fishFrame(0)
    , fish2Frame(0)
    , diverFrame(0)
    , bubblePixmap(":/images/smallbubble.png")
{
    ui->setupUi(this);

    // Load fish images and split them into 6 parts
    QPixmap fishPixmap(":/images/fish.png");
    QPixmap fish2Pixmap(":/images/fish2.png");
    QPixmap diverPixmap(":/images/diver.png");

    int frameWidth  = fishPixmap.width() /4;
    int frameHeight = fishPixmap.height()/2;

    for (int j = 0; j < 2; j++) {
        for (int i = 0; i < 4; ++i) {
            fishPixmaps.push_back(fishPixmap.copy(i * frameWidth, frameHeight * j, frameWidth, frameHeight));
        }
    }

    frameWidth  = fish2Pixmap.width() /2;
    frameHeight = fish2Pixmap.height()/3;

    for (int j = 0; j < 3; j++) {
        for (int i = 0; i < 2; ++i) {
            fish2Pixmaps.push_back(fish2Pixmap.copy(i * frameWidth, frameHeight * j, frameWidth, frameHeight));
        }
    }

    frameWidth  = diverPixmap.width();
    frameHeight = diverPixmap.height()/16;

    for (int i = 0; i < 16; ++i) {
        diverPixmaps.push_back(diverPixmap.copy(0, frameHeight * i, frameWidth, frameHeight));
    }

    // Set the background image
    ui->backgroundLabel->setPixmap(QPixmap(":/images/water_1080.png"));
    ui->backgroundLabel->setScaledContents(true);

    // Set the initial fish images
    ui->fishLabel->setPixmap(fishPixmaps[0]);
    ui->fishLabel->setScaledContents(true);

    ui->fish2Label->setPixmap(fish2Pixmaps[0]);
    ui->fish2Label->setScaledContents(true);

    // Set the diver image
    ui->diverLabel->setPixmap(diverPixmaps[0]);
    ui->diverLabel->setScaledContents(true);

    // Create timers for moving the fish
    moveTimer = new QTimer(this);
    connect(moveTimer, &QTimer::timeout, this, &MainWindow::moveFish);
    moveTimer->start(50);

    moveTimer2 = new QTimer(this);
    connect(moveTimer2, &QTimer::timeout, this, &MainWindow::moveFish2);
    moveTimer2->start(50);

    // Create timers for animating the fish
    animateTimer = new QTimer(this);
    connect(animateTimer, &QTimer::timeout, this, &MainWindow::animateFish);
    animateTimer->start(100);

    animateTimer2 = new QTimer(this);
    connect(animateTimer2, &QTimer::timeout, this, &MainWindow::animateFish2);
    animateTimer2->start(100);

    // Create timers for animating the diver
    animateTimer3 = new QTimer(this);
    connect(animateTimer3, &QTimer::timeout, this, &MainWindow::animateDiver);
    animateTimer3->start(100);

    cpuTimer = new QTimer(this);
    connect(cpuTimer, &QTimer::timeout, this, &MainWindow::updateClock);
    cpuTimer->start(1000); // 每秒更新一次时钟

    // Create timer for creating bubbles
    bubbleTimer = new QTimer(this);
    connect(bubbleTimer, &QTimer::timeout, this, &MainWindow::createBubble);
    bubbleTimer->start(1000);

    // 显示 CPU 使用率的标签
    cpuLabel = new QLabel(this);
    cpuLabel->setGeometry(580, 5, 200, 40);
    cpuLabel->setStyleSheet("font-size: 20px; color: red;");
    cpuLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    cpuUsage = new CPUUsage(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::moveFish()
{
    int x = ui->fishLabel->x() + 5;
    if (x > this->width()) {
        x = -ui->fishLabel->width();
        int y = QRandomGenerator::global()->bounded(this->height() - ui->fishLabel->height());
        ui->fishLabel->move(x, y);
    } else {
        ui->fishLabel->move(x, ui->fishLabel->y());
    }
}

void MainWindow::moveFish2()
{
    int x = ui->fish2Label->x() + 5;
    if (x > this->width()) {
        x = -ui->fish2Label->width();
        int y = QRandomGenerator::global()->bounded(this->height() - ui->fish2Label->height());
        ui->fish2Label->move(x, y);
    } else {
        ui->fish2Label->move(x, ui->fish2Label->y());
    }
}

void MainWindow::animateFish()
{
    fishFrame = (fishFrame + 1) % fishPixmaps.size();
    ui->fishLabel->setPixmap(fishPixmaps[fishFrame]);
}

void MainWindow::animateFish2()
{
    fish2Frame = (fish2Frame + 1) % fish2Pixmaps.size();
    ui->fish2Label->setPixmap(fish2Pixmaps[fish2Frame]);
}

void MainWindow::animateDiver()
{
    diverFrame = (diverFrame + 1) % diverPixmaps.size();
    ui->diverLabel->setPixmap(diverPixmaps[diverFrame]);
}

void MainWindow::updateClock()
{
    cpuLabel->setText(QString("CPU Usage: %1%").arg(cpuUsage->getCPUUsage(), 0, 'f', 2));
    update();
}

void MainWindow::createBubble()
{
    int bubbleCount = QRandomGenerator::global()->bounded(1, 4); // Random number of bubbles between 1 and 5
    for (int i = 0; i < bubbleCount; ++i) {
        int x = QRandomGenerator::global()->bounded(this->width());
        int y = this->height();
        int size = QRandomGenerator::global()->bounded(5, 32); // Random size between 10 and 50
        int xspeed = 0;
        int yspeed = -QRandomGenerator::global()->bounded(5, 20); // Random speed between 1 and 10
        Bubble* bubble = new Bubble(bubblePixmap, xspeed, yspeed, QPoint(x, y), size, this);
        bubbles.push_back(bubble);
        bubble->show();
        if (bubble->getcount() >= 20) {
            break;
        }
    }
}

以下是EGT

/*
 * Copyright (C) 2018 Microchip Technology Inc.  All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include <chrono>
#include <cmath>
#include <cstring>
#include <iostream>
#include <map>
#include <egt/ui>
#include <random>
#include <sstream>
#include <string>
#include <vector>

using namespace std;
using namespace egt;

class Bubble : public ImageLabel
{
public:
    Bubble(int xspeed, int yspeed, const Point& point) noexcept
        : ImageLabel(Image("file:smallbubble.png"), "", Rect(point, Size())),
          m_xspeed(xspeed),
          m_yspeed(yspeed)
    {
        flags().set(Widget::Flag::no_layout);
    }

    Bubble(const Bubble&) = default;
    Bubble(Bubble&&) = default;
    Bubble& operator=(const Bubble&) = default;
    Bubble& operator=(Bubble&&) = default;
    virtual ~Bubble() = default;

    bool animate()
    {
        bool visible = Rect(Point(0, 0), Application::instance().screen()->size()).intersect(box());

        if (visible)
        {
            Point to(box().point());
            to += Point(m_xspeed, m_yspeed);
            move(to);
        }

        return visible;
    }

private:

    Bubble() = delete;

    int m_xspeed;
    int m_yspeed;
};

class MainWindow : public TopWindow
{
public:
    MainWindow()
        : TopWindow(Size()),
          e1(r())
    {
        background(Image("file:water.png"));

        m_label = make_shared<Label>("Objects: 0",
                                     Rect(Point(10, 10),
                                          Size(150, 40)),
                                     AlignFlag::left | AlignFlag::center_vertical);
        m_label->color(Palette::ColorId::text, Palette::white);
        m_label->color(Palette::ColorId::bg, Palette::transparent);
        add(top(left(m_label)));

        m_sprite = make_shared<Sprite>(Image("file:diver.png"), Size(390, 312), 16, Point(0, 0));
        m_sprite->no_layout(true);
        add(m_sprite);
        m_sprite->show();
    }

    void handle(Event& event) override
    {
        TopWindow::handle(event);

        switch (event.id())
        {
        case EventId::raw_pointer_move:
            spawn(display_to_local(event.pointer().point));
            break;
        default:
            break;
        }
    }

    void spawn(const Point& p)
    {
        auto xspeed = 0;
        auto yspeed = speed_dist(e1);
        auto offset = offdist(e1);
        auto size = size_dist(e1);

        // has to move at some speed
        if (yspeed == 0)
            yspeed = 1;

        m_images.emplace_back(make_shared<Bubble>(xspeed, yspeed, p));
        auto& image = m_images.back();
        add(image);
        image->image_align(AlignFlag::expand_horizontal | AlignFlag::expand_vertical);
        image->resize_by_ratio(size);
        image->move(Point(p.x() - image->box().width() / 2 + offset,
                          p.y() - image->box().height() / 2 + offset));
        objects_changed();
    }

    void animate()
    {
        for (auto x = m_images.begin(); x != m_images.end();)
        {
            auto& image = *x;
            if (!image->animate())
            {
                image->detach();
                x = m_images.erase(x);
                objects_changed();
            }
            else
            {
                x++;
            }
        }
    }

    void objects_changed()
    {
        ostringstream ss;
        ss << "Objects: " << m_images.size();
        m_label->text(ss.str());
    }

    vector<shared_ptr<Bubble>> m_images;
    shared_ptr<Label> m_label;
    shared_ptr<Sprite> m_sprite;

    std::random_device r;
    std::default_random_engine e1;
    std::uniform_int_distribution<int> speed_dist{-20, -1};
    std::uniform_int_distribution<int> offdist{-20, 20};
    std::uniform_int_distribution<int> size_dist{10, 100};
};

int main(int argc, char** argv)
{
    Application app(argc, argv, "water");
#ifdef EXAMPLEDATA
    add_search_path(EXAMPLEDATA);
#endif
    MainWindow win;

    vector<Sprite*> sprites;

#define SPRITE1
#ifdef SPRITE1
    Sprite sprite1(Image("file:fish.png"), Size(252, 209), 8, Point(0, 0));
    sprite1.no_layout(true);
    win.add(sprite1);
    sprite1.show();
    sprites.push_back(&sprite1);
#endif

#define SPRITE2
#ifdef SPRITE2
    Sprite sprite2(Image("file:fish2.png"), Size(100, 87), 6, Point(0, 0));
    sprite2.no_layout(true);
    win.add(sprite2);
    sprite2.show();
    sprites.push_back(&sprite2);
#endif

    sprites.push_back(win.m_sprite.get());

    PeriodicTimer animatetimer(std::chrono::milliseconds(30));
    animatetimer.on_timeout([&win]()
    {
        win.animate();
    });
    animatetimer.start();

    PeriodicTimer animatetimer2(std::chrono::milliseconds(100));
    animatetimer2.on_timeout([&sprites]()
    {
        for (auto& sprite : sprites)
            sprite->advance();
    });
    animatetimer2.start();

    PeriodicTimer spawntimer(std::chrono::seconds(1));
    spawntimer.on_timeout([&win]()
    {
        if (win.m_images.size() > 30)
            return;

        static std::uniform_int_distribution<int> xoffdist(-win.width() / 2, win.width() / 2);
        int offset = xoffdist(win.e1);

        static std::uniform_int_distribution<int> count_dist(1, 10);
        int count = count_dist(win.e1);

        Point p(win.box().center());
        p.y(win.box().height());
        p.x(p.x() + offset);

        while (count--)
            win.spawn(p);
    });
    spawntimer.start();

#ifdef SPRITE1
    PropertyAnimator a1(-sprite1.size().width(), Application::instance().screen()->size().width(),
                        std::chrono::milliseconds(10000),
                        easing_linear);
    a1.on_change([&sprite1](PropertyAnimator::Value value){
            sprite1.x(value);
        });
    a1.start();

    PeriodicTimer floattimer(std::chrono::milliseconds(1000 * 12));
    floattimer.on_timeout([&a1, &sprite1, &win]()
    {

        static std::uniform_int_distribution<int> yoffdist(0, win.height() - sprite1.size().height());
        int y = yoffdist(win.e1);

        sprite1.move(Point(-sprite1.size().width(), y));
        a1.start();
    });
    floattimer.start();
#endif

#ifdef SPRITE2
    PropertyAnimator a2(-sprite2.size().width(), Application::instance().screen()->size().width(),
                        std::chrono::milliseconds(12000),
                        easing_linear);
    a2.on_change([&sprite2](PropertyAnimator::Value value){
            sprite2.x(value);
        });
    a2.start();

    PeriodicTimer floattimer2(std::chrono::milliseconds(1000 * 15));
    floattimer2.on_timeout([&a2, &sprite2, &win]()
    {
        static std::uniform_int_distribution<int> yoffdist(0, win.height() - sprite2.size().height());
        int y = yoffdist(win.e1);

        sprite2.move(Point(-sprite2.size().width(), y));
        a2.start();
    });
    floattimer2.start();
#endif

    Label label1("CPU: ----");
    label1.color(Palette::ColorId::text, Palette::red);
    label1.color(Palette::ColorId::bg, Palette::transparent);
    win.add(bottom(left(label1)));

    egt::experimental::CPUMonitorUsage tools;
    PeriodicTimer cputimer(std::chrono::seconds(1));
    cputimer.on_timeout([&label1, &tools]()
    {
        tools.update();
        ostringstream ss;
        ss << "CPU: " << static_cast<int>(tools.usage()) << "%";
        label1.text(ss.str());
    });
    cputimer.start();

    win.show();

    return app.run();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信息系统管理工程师教程第2版(2024年最新版)

信息系统管理工程师教程第2版 目录 第 1 章 信息化发展 第 2 章 信息技术发展 第 3 章 信息系统架构 第 4 章 信息系统治理 第 5 章 信息技术服务管理 第 6 章 软件开发过程管理 第 7 章 系统集成实施管理 第 8 章 信息系统运维管理 第 9 章 云服务及其运营…

Science Robotics让软机器人“活”得更久的3D打印!

软机器人硬件在医疗、探索无结构环境等领域有广泛应用&#xff0c;但其生命周期有限&#xff0c;导致资源浪费和可持续性差。软机器人结合软硬组件&#xff0c;复杂组装和拆卸流程使其难以维修和升级。因此&#xff0c;如何延长软机器人的生命周期并提高其可持续性成为亟待解决…

通过Dockerfile来实现项目可以指定读取不同环境的yml包

通过Dockerfile来实现项目可以指定读取不同环境的yml包 1. 挂载目录2. DockerFile3. 运行脚本deploy.sh4. 运行查看日志进入容器 5. 接口测试修改application-dev.yml 6. 优化Dockerfile7. 部分参数解释8. 优化不同环境下的日志也不同调整 Dockerfile修改部署脚本 deploy.sh重新…

AutoSar架构学习笔记

1.AUTOSAR&#xff08;Automotive Open System Architecture&#xff0c;汽车开放系统架构&#xff09;是一个针对汽车行业的软件架构标准&#xff0c;旨在提升汽车电子系统的模块化、可扩展性、可重用性和互操作性。AUTOSAR的目标是为汽车电子控制单元&#xff08;ECU&#xf…

超越YOLO11!DEIM:先进的实时DETR目标检测

DEIM: DETR with Improved Matching for Fast Convergence arXiv: https://arxiv.org/abs/2412.04234 Project webpage&#xff1a;https://www.shihuahuang.cn/DEIM/ GitHub&#xff1a;https://github.com/ShihuaHuang95/DEIM 1 背景&#xff1a;DETR目标检测框架 目标检…

深入理解 Java 接口的回调机制

前言 回调是一种非常重要的编程技术&#xff0c;它广泛应用于事件驱动的编程、异步任务和框架设计中。在 Java 中&#xff0c;回调机制通常通过 接口 来实现。本篇博客将详细解析 Java 接口的回调原理、实现方式&#xff0c;以及实际开发中的应用场景。 泪崩了&#xff0c;期末…

二、用例图

二、用例图 (一&#xff09;、用例图的基本概念 1、用例图的定义&#xff1a; 用例图是表示一个系统中用例与参与者关系之间的图。它描述了系统中相关的用户和系统对不同用户提供的功能和服务。 用例图相当于从用户的视角来描述和建模整个系统&#xff0c;分析系统的功能与…

【软考网工笔记】计算机基础理论与安全——网络安全

病毒 Melissa 宏病毒 1. 是一种快速传播的能够感染那些使用MS Word 97 和MS Office 2000 的计算机宏病毒。 2. 前面有**Macro** 表示这是宏病毒&#xff1b; 3. 宏病毒可以感染后缀为.xls的文件&#xff1b;Worm 蠕虫病毒 1. 通常是通过网络或者系统漏洞进行传播。 2. 利用信…

STM32 拓展 低功耗案例3:待机模式 (register)

需求描述 寄存器操作进入待机模式。待机模式的唤醒方式比较有限。我们这次使用WKUP引脚的上升沿唤醒。PA0就是WKUP引脚。 当然PA0仍然需要工作在下拉输入模式&#xff0c;只有这样当按键按下的时候才会有一个上升沿。 由于我们电路中PA0已经连接了LED1&#xff0c;所以要产生…

windows中硬件加速gpu计划开启cpu的使用率居高不下

1.加速gpu计划开启在任务管理器的gpu选项中看不到cuda选项&#xff0c;这给我们进行深度学习训练和推理带来很大影响。 2.开启硬件加速CPU的占用率明显增高&#xff0c;特别用GPU进行实时视频流解码时就不会分配给GPU解码&#xff0c;造成cpu占用居高不下。不利于深度学习训练…

【Go】运行自己的第一个Go程序

运行自己的第一个Go程序 一、Go语言的安装Go环境安装查看是否安装成功配置GOPROXY(代理) 二、Goland安装三、Goland破解四、新建项目 开一篇专栏记录学习Go的过程&#xff0c;一门新语言从hello world开始&#xff0c;这篇文章详细讲解Go语言环境搭建及hello world实现 一、Go语…

提升汽车金融租赁系统的效率与风险管理策略探讨

内容概要 在汽车金融租赁系统这个复杂的生态中&#xff0c;提升整体效率是每个企业都渴望达成的目标。首先&#xff0c;优化业务流程是实现高效运行的基础。通过分析目前的流程&#xff0c;找出冗余环节并进行简化&#xff0c;能够帮助企业缩短审批时间&#xff0c;提高客户满…

计算机网络 (25)IPV6

前言 IPv6&#xff0c;全称为“互联网协议第6版”&#xff08;Internet Protocol Version 6&#xff09;&#xff0c;是由互联网工程任务组&#xff08;IETF&#xff09;设计的用于替代IPv4的下一代IP协议。 一、产生背景 IPv4&#xff0c;即互联网协议第4版&#xff0c;是现行…

嵌入式系统(将软件嵌入到硬件里面)

目录 Linux起源 查看操作系统的版本 查看内核的版本&#xff1a; 内核系统架构 系统关机或重启命令 关机&#xff1a; 重启&#xff1a; linux下的软件安装 两种软件包管理机制&#xff1a; deb软件包分为两种&#xff1a; 软件包的管理工具&#xff1a;dpkg apt 1…

Conda 安装 Jupyter Notebook

文章目录 1. 安装 Conda下载与安装步骤&#xff1a; 2. 创建虚拟环境3. 安装 Jupyter Notebook4. 启动 Jupyter Notebook5. 安装扩展功能&#xff08;可选&#xff09;6. 更新与维护7. 总结 Jupyter Notebook 是一款非常流行的交互式开发工具&#xff0c;尤其适合数据科学、机器…

web实操9——session

概念 数据保存在服务器HttpSession对象里。 session也是域对象&#xff0c;有setAttribute和getAttribute方法 快速入门 代码 获取session和塞入数据&#xff1a; 获取session获取数据&#xff1a; 请求存储&#xff1a; 请求获取&#xff1a; 数据正常打印&#xff1a…

如何在电脑上使用 FaceTime

如今&#xff0c;视频通话已成为与朋友、家人和同事保持联系的重要组成部分。 FaceTime 是 Apple 推出的一款功能丰富的视频通话应用程序。它以其简单性和视频质量而闻名。但如果您想在 PC 上使用 FaceTime该怎么办&#xff1f;虽然 FaceTime 仅适用于 Apple 设备&#xff0c;但…

(框架漏洞)

1.Thinkphp 1.Thinkphp5x远程命令执⾏及getshell 搭建靶场环境 vulhub/thinkphp/5-rce docker-compose up -d #启动环境 ?sindex/think\app/invokefunction&functioncall_user_func_array&vars[0]system&vars[1][]whoami ?s/Index/\think\app/invokefunctio…

探秘Kafka源码:关键内容解析

文章目录 一、以kafka-3.0.0为例1.1安装 gradle 二、生产者源码2.1源码主流程图2.2 初始化2.3生产者sender线程初始化2.4 程序入口2.5生产者 main 线程初始化2.6 跳转到 KafkaProducer构造方法 一、以kafka-3.0.0为例 打开 IDEA&#xff0c;点击 File->Open…->源码包解…

动态库dll与静态库lib编程4:MFC规则DLL讲解

文章目录 前言一、说明二、具体实现2.1新建项目2.2 模块切换的演示 总结 前言 动态库dll与静态库lib编程4&#xff1a;MFC规则DLL讲解。 一、说明 1.前面介绍的均为Win32DLL&#xff0c;即不使用MFC的DLL。 2.MFC规则DLL的特点&#xff1a;DLL内部可以使用MFC类库、可以被其他…