焦作建设企业网站公司,营销咨询是做什么的,wordpress 外链统计,做ppt模版的网站在工业软件、设备配置工具或上位机系统中#xff0c;**固件升级#xff08;Firmware Upgrade#xff09;**是一个非常常见但又容易出问题的功能点。
典型需求包括#xff1a;
调用厂商提供的 Windows DLL 执行升级升级过程不能阻塞 UI实时显示升级进度升级过程中禁止用户误…在工业软件、设备配置工具或上位机系统中**固件升级Firmware Upgrade**是一个非常常见但又容易出问题的功能点。典型需求包括调用厂商提供的 Windows DLL 执行升级升级过程不能阻塞 UI实时显示升级进度升级过程中禁止用户误操作升级完成后给出明确反馈本文通过一个真实工程级示例完整讲解如何使用Qt Windows DLL实现一个可靠的固件升级进度弹窗。一、应用场景说明为什么要这样做在实际项目中固件升级逻辑通常由硬件厂商提供的 DLL完成例如LVDS / V-by-One 显示控制器FPGA / MCU 配置工具工控采集设备显示驱动板卡升级程序Qt 作为上位机 UI 层只负责加载 DLL调用升级接口显示升级状态控制用户交互升级过程本身必须在后台线程执行否则 UI 会卡死。二、设计思路概览整体架构如下使用LoadLibrary / GetProcAddress动态加载 DLL在后台线程中调用升级函数通过定时器轮询 DLL 中的升级进度接口使用QDialog QProgressBar显示进度升级完成后释放 DLL 并允许用户关闭窗口这是工业软件中最常见、最稳定的一种升级实现方式。三、DLL 接口定义说明假设厂商 DLL 中提供如下接口// 启动固件升级voidUploadProgram(constchar*filePath);// 查询升级进度0 ~ 100intGetUploadProgramSchedule();Qt 端通过函数指针方式调用。四、核心实现代码完整案例1. 函数整体结构voidLVDSVbyOneSignalCollector::firmwareUpInformationBox(QString path)该函数的职责是弹出升级对话框启动固件升级显示升级进度等待升级完成2. 动态加载 DLLHMODULE hDllLoadLibraryA(LVDSVbyOneSignalCollectorDLL.dll);if(!hDll){return;}autopUploadProgram(PFN_UploadProgram)GetProcAddress(hDll,UploadProgram);autopGetUploadProgramSchedule(PFN_GetUploadProgramSchedule)GetProcAddress(hDll,GetUploadProgramSchedule);if(!pUploadProgram||!pGetUploadProgramSchedule){FreeLibrary(hDll);return;}为什么使用动态加载DLL 由第三方提供可选功能模块避免启动时强依赖方便版本替换3. 构建升级 UI不可中断QDialog*dialognewQDialog(nullptr);dialog-setWindowTitle(tr(Firmware Upgrade));dialog-setWindowModality(Qt::ApplicationModal);dialog-setFixedSize(360,140);// 禁止右上角关闭dialog-setWindowFlags(dialog-windowFlags()~Qt::WindowCloseButtonHint);这是一个应用级模态窗口升级过程中用户无法操作主界面。4. UI 元素布局QLabel*labelnewQLabel(tr(Upgrading firmware, please wait...),dialog);QProgressBar*progressBarnewQProgressBar(dialog);progressBar-setRange(0,100);progressBar-setValue(0);QPushButton*btnOknewQPushButton(tr(OK),dialog);btnOk-setEnabled(false);升级未完成前OK 按钮不可点击避免误关闭。5. 后台线程执行升级关键QFuturevoidfutureQtConcurrent::run([](){pUploadProgram(rInfor.filePath);});这里使用QtConcurrent::run的目的非常明确避免 UI 阻塞升级逻辑与界面解耦不需要手写 QThread这是 Qt 工程中推荐的做法之一。6. 使用 QTimer 轮询升级进度QTimer*timernewQTimer(dialog);QObject::connect(timer,QTimer::timeout,dialog,[](){intvaluepGetUploadProgramSchedule();// 0~100progressBar-setValue(value);if(future.isFinished()){timer-stop();progressBar-setValue(100);label-setText(tr(Firmware upgrade completed.));btnOk-setEnabled(true);FreeLibrary(hDll);}});timer-start(300);这种设计的优点不需要 DLL 回调逻辑简单、稳定工业项目中极其常见7. 升级完成后退出QObject::connect(btnOk,QPushButton::clicked,dialog,[](){dialog-accept();dialog-deleteLater();});只有在升级完成后用户才能关闭窗口。五、工程级注意事项非常重要1️⃣ 文件路径生命周期问题std::string strpath.toStdString();rInfor.filePathstr.c_str();如果 DLL 在内部异步使用该指针这里存在风险。更安全的方式是保证字符串长期有效如成员变量或深拷贝。2️⃣ DLL 卸载时机FreeLibrary必须确保升级线程完全结束DLL 内部没有残留线程否则可能导致随机崩溃。3️⃣ 建议增加失败与超时处理生产环境中建议补充升级失败状态超时检测错误码提示日志记录六、总结本文通过一个真实工业项目中的固件升级案例展示了Qt 如何调用 Windows DLL如何在后台线程执行耗时任务如何安全地显示升级进度如何设计不可中断的升级 UI这种结构在工业上位机 / 设备工具 / 显示控制软件中非常通用具有很高的工程参考价值。voidLVDSVbyOneSignalCollector::firmwareUp(){QMessageBox msgBox;msgBox.setWindowTitle(提示);msgBox.setText(你确定要继续吗);msgBox.setIcon(QMessageBox::Question);msgBox.setStandardButtons(QMessageBox::Ok|QMessageBox::Cancel);msgBox.button(QMessageBox::Ok)-setText(更新);msgBox.button(QMessageBox::Cancel)-setText(取消);intretmsgBox.exec();if(retQMessageBox::Ok){qDebug()用户点击了确定按钮;QString pathui.lineEdit_bootPath-text();QFileInfofileInfo(path);if(fileInfo.exists()){if(fileInfo.isDir()){qDebug()路径是有效的目录;}elseif(fileInfo.isFile()){qDebug()路径是有效的文件;}}else{qDebug()路径无效;QMessageBox::information(this,path,QString(The path is invalid.));return;}firmwareUpInformationBox(path);}elseif(retQMessageBox::Cancel){qDebug()用户点击了关闭按钮;}}voidLVDSVbyOneSignalCollector::firmwareUpInformationBox(QString path){HMODULE hDllLoadLibraryA(LVDSVbyOneSignalCollectorDLL.dll);if(!hDll){return;}PFN_UploadProgram pUploadProgram(PFN_UploadProgram)GetProcAddress(hDll,UploadProgram);PFN_GetUploadProgramSchedule pGetUploadProgramSchedule(PFN_GetUploadProgramSchedule)GetProcAddress(hDll,GetUploadProgramSchedule);if(!pUploadProgram||!pGetUploadProgramSchedule){FreeLibrary(hDll);return;}std::string strpath.toStdString();rInfor.filePathstr.c_str();/* UI */QDialog*dialognewQDialog(nullptr);dialog-setWindowTitle(tr(Firmware Upgrade));dialog-setWindowModality(Qt::ApplicationModal);dialog-setFixedSize(360,140);// 禁止关闭dialog-setWindowFlags(dialog-windowFlags()~Qt::WindowCloseButtonHint);QLabel*labelnewQLabel(tr(Upgrading firmware, please wait...),dialog);QProgressBar*progressBarnewQProgressBar(dialog);progressBar-setRange(0,100);progressBar-setValue(0);QPushButton*btnOknewQPushButton(tr(OK),dialog);btnOk-setEnabled(false);// 完成前不可点击QVBoxLayout*layoutnewQVBoxLayout(dialog);layout-addWidget(label);layout-addWidget(progressBar);layout-addWidget(btnOk,0,Qt::AlignRight);dialog-setLayout(layout);dialog-show();/* 后台线程 */QFuturevoidfutureQtConcurrent::run([](){pUploadProgram(rInfor.filePath);});/* 进度轮询 */QTimer*timernewQTimer(dialog);QObject::connect(timer,QTimer::timeout,dialog,[](){intvaluepGetUploadProgramSchedule();// 0~100progressBar-setValue(value);if(future.isFinished()){timer-stop();progressBar-setValue(100);label-setText(tr(Firmware upgrade completed.));btnOk-setEnabled(true);FreeLibrary(hDll);}});timer-start(300);/* 完成后退出 */QObject::connect(btnOk,QPushButton::clicked,dialog,[](){dialog-accept();dialog-deleteLater();});}