Files
eUi/src/launcher/main.cpp
T
RCiRoot f50bcb30d1 V20260127-2.3.11
存图时会缓存创建文件夹的路径以防重复创建。
悬停在右侧缺陷柱状图时会出现具体缺陷名,
部分逻辑以及保护优化。
2026-01-28 10:49:49 +08:00

369 lines
16 KiB
C++

#include <windows.h>
#include "client/windows/handler/exception_handler.h"
#include <global.h>
#include <QApplication>
#include <QException>
#include <QSystemSemaphore>
#include <QSharedMemory>
#include <QMessageLogger>//日志
#include <QDebug>
#include <QDateTime>
#include <qmessagebox.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <QMetaType>
#include <appCore.hpp>
#include <QGuiApplication>
#include <windows.h> // GetModuleFileName, ShellExecuteEx, SW_NORMAL 等
#include <tchar.h> // TCHAR 相关操作
#include <shellapi.h> // SHELLEXECUTEINFO 结构体
#include <iostream> // std::cout (如果需要打印信息)
#include <tlhelp32.h> // CreateToolhelp32Snapshot, Process32First, Process32Next
#include <filesystem> // std::filesystem::path
#include <thread> // std::thread for restart functionality
#include <chrono> // std::chrono for time operations
#include <memory> // std::unique_ptr for smart pointer management
#include <GUI/mainwindow.h>
#include <frontendSignalHub.h>
#pragma region 程序启动功能
// 获取当前exe文件名
std::string getCurrentExeName() {
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
std::filesystem::path path(exePath);
return path.filename().string();
}
// 枚举窗口回调函数,用于置顶指定进程的窗口
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
DWORD* targetPid = (DWORD*)lParam;
DWORD windowPid;
GetWindowThreadProcessId(hwnd, &windowPid);
if (windowPid == *targetPid && IsWindowVisible(hwnd)) {
// 将窗口置顶并激活
SetForegroundWindow(hwnd);
ShowWindow(hwnd, SW_RESTORE);
return FALSE; // 停止枚举
}
return TRUE; // 继续枚举
}
// 检查应用是否已在运行,如果是则置顶
bool appIsRuning(){
std::string currentExeName = getCurrentExeName();
DWORD currentPid = GetCurrentProcessId();
// 创建进程快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return true; // 如果无法创建快照,允许启动
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
bool foundOtherInstance = false;
DWORD otherInstancePid = 0;
// 遍历进程
if (Process32First(hSnapshot, &pe32)) {
do {
// 比较进程名(忽略大小写)
if (_stricmp(pe32.szExeFile, currentExeName.c_str()) == 0 &&
pe32.th32ProcessID != currentPid) {
foundOtherInstance = true;
otherInstancePid = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
if (foundOtherInstance) {
// 找到其他实例,将其置顶
EnumWindows(EnumWindowsProc, (LPARAM)&otherInstancePid);
return false; // 返回false表示已有实例在运行
}
return true; // 没有其他实例在运行
}
#pragma endregion
static bool dumpCallback(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded) {
QString dumpFile = QString::fromWCharArray(dump_path) + "\\" + QString::fromWCharArray(minidump_id) + ".dmp";
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
if (succeeded) {
qDebug() << "========== 程序崩溃 ==========" << timestamp;
qDebug() << "崩溃转储文件已生成:" << dumpFile;
if (exinfo && exinfo->ExceptionRecord) {
DWORD exceptionCode = exinfo->ExceptionRecord->ExceptionCode;
qDebug() << "异常代码:" << Qt::hex << Qt::showbase << exceptionCode;
qDebug() << "异常地址:" << Qt::hex << Qt::showbase << (quintptr)exinfo->ExceptionRecord->ExceptionAddress;
// 解释常见的异常代码
QString exceptionType;
switch (exceptionCode) {
case EXCEPTION_ACCESS_VIOLATION: exceptionType = "访问违规 (Access Violation)"; break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: exceptionType = "数组越界 (Array Bounds Exceeded)"; break;
case EXCEPTION_DATATYPE_MISALIGNMENT: exceptionType = "数据类型未对齐 (Datatype Misalignment)"; break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO: exceptionType = "浮点除零 (Float Divide by Zero)"; break;
case EXCEPTION_INT_DIVIDE_BY_ZERO: exceptionType = "整数除零 (Integer Divide by Zero)"; break;
case EXCEPTION_STACK_OVERFLOW: exceptionType = "栈溢出 (Stack Overflow)"; break;
case EXCEPTION_ILLEGAL_INSTRUCTION: exceptionType = "非法指令 (Illegal Instruction)"; break;
default: exceptionType = "未知异常"; break;
}
qDebug() << "异常类型:" << exceptionType;
// 记录更多上下文信息
if (exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
exinfo->ExceptionRecord->NumberParameters >= 2) {
ULONG_PTR operation = exinfo->ExceptionRecord->ExceptionInformation[0];
ULONG_PTR address = exinfo->ExceptionRecord->ExceptionInformation[1];
QString operationType = (operation == 0) ? "读取" : (operation == 1) ? "写入" : "执行";
qDebug() << "访问类型:" << operationType << "地址:" << Qt::hex << Qt::showbase << address;
}
}
// 记录当前线程ID
qDebug() << "崩溃线程ID:" << GetCurrentThreadId();
qDebug() << "==============================";
// 程序崩溃后自动重启
qDebug() << "程序即将自动重启...";
} else {
qDebug() << "========== 崩溃转储失败 ==========" << timestamp;
qDebug() << "生成崩溃转储文件失败!";
qDebug() << "程序即将自动重启...";
qDebug() << "==============================";
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
restartProgram(false, true, 5000);
return succeeded;
}
bool checkResourceExists(const QString& resourcePath) {
if (QFile::exists(resourcePath)) {
qDebug() << "文件存在:" << resourcePath;
return true;
}
else {
qDebug() << "文件不存在:" << resourcePath;
return false;
}
}
void connectFrontSignals(appCore* _core, MainWindow* _MainWindow, fSignalHub* bridge) {
QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::stdLogSignal,
_MainWindow->_logWidget, &logWidget::recvStdLogMsg);
QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::qtLogSignal,
_MainWindow->_logWidget, &logWidget::recvQtLogMsg);
QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::mainWindowStdLogSignal,
_MainWindow->_displayWidget, &displayWidget::recvMainWindowStdLogMsg);
QObject::connect(_core->_logService->getLogWidget(), &logToQtWidget::loadingWindow_appendConsoleLog,
_MainWindow, [=](const QString& text) {_MainWindow->_loadingWidget.appendConsoleLog(text); });
//BackEnd To Front
//等待界面
//波形图
QObject::connect(bridge, &fSignalHub::triggerAndCaptureImage,
_core->_backEnd.backendPtr, &IBackend::triggerAndCaptureImage,Qt::DirectConnection);
QObject::connect(bridge, &fSignalHub::getCameraNames,
_core->_backEnd.backendPtr, &IBackend::getCameraNames, Qt::DirectConnection);
QObject::connect(bridge, &fSignalHub::getAllParams,
_core->_backEnd.backendPtr, &IBackend::getAllParams, Qt::DirectConnection);
QObject::connect(bridge, &fSignalHub::editParam,
_core->_backEnd.backendPtr, &IBackend::editParam, Qt::DirectConnection);
QObject::connect(bridge, &fSignalHub::saveMissionJson,
_core,[=]() {
auto& config = appConfig::getInstance();
config.missionJson["backend"] = _core->_backEnd.backendPtr->getBackendJson();
config.saveSettingJson();
}, Qt::DirectConnection);
QObject::connect(bridge, &fSignalHub::restartInit,[=]() {
appConfig::getInstance().exitWithRestart = true;
QApplication::quit();
});
}
void connectBackSignals(appCore* _core, MainWindow* _MainWindow, bSignalHub* bridge) {
//等待界面
QObject::connect(bridge, &bSignalHub::loadingWindow_appendInitLog,
_MainWindow, [=](const QString& text, const QColor& color) {_MainWindow->_loadingWidget.appendInitLog(text, color); });
QObject::connect(bridge, &bSignalHub::loadingWindow_modifyLog,
_MainWindow, [=](int col, const QString& text, const QColor& color) {_MainWindow->_loadingWidget.modifyLog(col, text, color); });
QObject::connect(bridge, &bSignalHub::loadingWindow_clearLog,
_MainWindow, [=]() {_MainWindow->_loadingWidget.clearLog(); });
QObject::connect(bridge, &bSignalHub::pieWidgetModifyData,
_MainWindow, [=](int modifyOkData, int modiftNgData) {_MainWindow->_displayWidget->_dsStatsWidget->modifyData(modifyOkData, modiftNgData); });
QObject::connect(bridge, &bSignalHub::histogramWidgetAddData,
_MainWindow, [=](int modifyOkData, int modiftNgData,std::vector<std::string>defects)
{_MainWindow->_displayWidget->_dayNightShiftHistogramWidget->addDefect(modifyOkData, modiftNgData,defects); });
QObject::connect(bridge, &bSignalHub::waveFormAddData,
_MainWindow, [=](QString windowName, double value)
{_MainWindow->_SummaryDataPage.addData(windowName, value); });
QObject::connect(bridge, &bSignalHub::setPlcConnectionError,
_MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setPlcDisconnected(); });
QObject::connect(bridge, &bSignalHub::setPlcConnectionOk,
_MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setPlcConnected(); });
QObject::connect(bridge, &bSignalHub::setCamConnectionError,
_MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setCamDisconnected(); });
QObject::connect(bridge, &bSignalHub::setCamConnectionOk,
_MainWindow, [=]() {_MainWindow->_displayWidget->_toolBarWidget->_ConnectionWidget->setCamConnected(); });
//登录界面
QObject::connect(bridge, &bSignalHub::initResult,
_MainWindow, &MainWindow::recvInitFinished);
QObject::connect(bridge, &bSignalHub::initResult,
_core, &appCore::recvInitFinished);
//展示界面//主界面
QObject::connect(bridge, &bSignalHub::displayWidget_sendImg,
_MainWindow, &MainWindow::recvPixmapImageWidget);
//波形图
QObject::connect(bridge, &bSignalHub::summaryData_addData,
_MainWindow, &MainWindow::slot_summaryData_addData);
//排障
QObject::connect(bridge, &bSignalHub::runCommand_addBtn,
&_MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::addBtn);
QObject::connect(&_MainWindow->_displayWidget->_runCommandWidget,
&runCommandWidget::excuteCommandPreset,
[=](QString uuid) {_core->_backEnd.backendPtr->excuteCliCommandPreset(uuid); });
QObject::connect(bridge, &bSignalHub::runCommand_addPlcValueViewer,
&_MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::addPlcValueViewer);
QObject::connect(bridge, &bSignalHub::runCommand_refeshPlcValueViewer,
&_MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::refreshPlcValueViewer);
//性能监测
QObject::connect(bridge, &bSignalHub::sendTriggerManagerLoopData,
_MainWindow->_displayWidget->_softwareDataDisplay, &softwareDataDisplay::onTriggerSateChanged);
QObject::connect(bridge, &bSignalHub::saveMissionJson,
_core,[=]() {
auto& config = appConfig::getInstance();
config.missionJson["backend"] = _core->_backEnd.backendPtr->getBackendJson();
config.saveSettingJson();
}, Qt::DirectConnection);
}
int main(int argc, char* argv[])
{
try {
#pragma region 设置显示控制栏
disableConsoleSelection();
HWND hWnd = GetConsoleWindow();
ShowWindow(hWnd, SW_SHOW);
#pragma endregion
#pragma region 启动breakPad崩溃捕获
std::wstring dumpPath = L"./dumps";
CreateDirectoryW(dumpPath.c_str(), nullptr);
// 初始化 breakpad
auto eh = std::make_unique<google_breakpad::ExceptionHandler>(
dumpPath,
/*FilterCallback*/ nullptr,
dumpCallback,
/*context*/ nullptr,
google_breakpad::ExceptionHandler::HANDLER_ALL
);
#pragma endregion
appCore _core;
auto& config = appConfig::getInstance();
config.consoleHandle = hWnd;
auto bridge = fSignalHub::getInstance(); // 创建 C++ 对象
//检测是否已运行
if (appIsRuning() == false)
exit(0);
//////////
#pragma region 注册信号槽变量
qRegisterMetaType<cv::Mat*>("matPtr");
qRegisterMetaType<std::string>("stdString");
qRegisterMetaType<historyPack>("historyPack");
qRegisterMetaType<Qt::GlobalColor>("QtGlobalColor");
qRegisterMetaType<showImgPack>("showImgPack");
qRegisterMetaType<initStatus>("initStatus");
qRegisterMetaType<cv::Mat>("mat");
qRegisterMetaType< std::vector<cv::Mat>*>("vecmatptr");
qRegisterMetaType<std::vector<std::string>>("vectorstring");
qRegisterMetaType<std::vector<std::pair<QString, int>>>("constvpqi");
qRegisterMetaType<PlcValueViewerStruct>("PlcValueViewerStruct");
qRegisterMetaType<std::vector<std::pair<QString, QVariant>>>("vecQStringQVarint");
qRegisterMetaType<std::vector<std::pair<QString, QVariant>>*>("vecQStringQVarintPtr");
#pragma endregion
QApplication a(argc, argv);
_core.initDatabase(); // 初始化数据库
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() + "/sqldrivers");
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
MainWindow w(&config,bridge, config.missionJson);
w.show();
QThread::msleep(100);
// 创建后端对象
_core._backEnd.loadCore(config.dataBase, config.missionJson["backend"]); // 加载核心功能
connectFrontSignals(&_core, &w, bridge); // 连接前端UI的信号和槽
connectBackSignals(&_core, &w, &_core._backEnd.backendPtr->_signalHub); // 连接前端UI的信号和槽
w.registerQuitFunc([&]() {
auto& config = appConfig::getInstance();
_core._backEnd.releaseCore(config.missionJson["backend"]);
QThread::msleep(100);
if (config.dataBase) delete config.dataBase;
config.dataBase = nullptr;
});
int qtRes = a.exec();
if (config.exitWithRestart) {
ShowWindow(hWnd, SW_SHOW);
std::cout << "程序将在五秒后重启..." << std::endl;
restartProgram(false,true,5000);
}
qDebug() << "程序退出,返回值" << qtRes;
if (qtRes != 0) {
qDebug() << "返回值不为0,非正常退出,即将重启程序";
restartProgram(false, true, 5000);
}
QThread::msleep(200);
return qtRes;
}
catch (const std::exception& e) {
// C++标准异常处理
qCritical() << "========== C++异常捕获 ==========";
qCritical() << "异常信息:" << e.what();
qCritical() << "==============================";
restartProgram(false, true, 5000);
return -1;
}
catch (const QException& e) {
// Qt异常处理
qCritical() << "========== Qt异常捕获 ==========";
qCritical() << "Qt异常信息:" << e.what();
qCritical() << "==============================";
restartProgram(false, true, 5000);
return -3;
}
catch (...) {
// 捕获所有其他异常
qCritical() << "========== 未知异常捕获 ==========";
qCritical() << "捕获到未知类型的异常";
qCritical() << "==============================";
restartProgram(false, true, 5000);
return -2;
}
return -99;
}