main.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include <QApplication>
  2. #include <QCoreApplication>
  3. #include <QCommandLineParser>
  4. #include <QDebug>
  5. #include <QDir>
  6. #include <QLocale>
  7. #include <QProcess>
  8. #include <QSettings>
  9. #include <QStandardPaths>
  10. #include <QTranslator>
  11. #include "hostthread.h"
  12. #include "messagequeue.h"
  13. #include "processthread.h"
  14. #include "qdatetime.h"
  15. #include "qobject.h"
  16. #include "qtsingleapplication.h"
  17. #include "updaterthread.h"
  18. #include "websocketclient.h"
  19. std::vector<unsigned long> GetProcessIDsByName(const std::wstring &processName)
  20. {
  21. std::vector<unsigned long> pids;
  22. // 创建进程快照
  23. HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  24. if (hSnapshot == INVALID_HANDLE_VALUE) {
  25. //std::cerr << "Failed to take snapshot of processes" << Qt::endl;
  26. return pids;
  27. }
  28. // 设置进程信息结构体
  29. PROCESSENTRY32 pe32;
  30. pe32.dwSize = sizeof(PROCESSENTRY32);
  31. // 获取第一个进程
  32. if (Process32First(hSnapshot, &pe32)) {
  33. do {
  34. // 检查进程名是否匹配
  35. if (processName == pe32.szExeFile) {
  36. pids.push_back(pe32.th32ProcessID); // 存储匹配的进程ID
  37. }
  38. } while (Process32Next(hSnapshot, &pe32)); // 获取下一个进程
  39. }
  40. // 关闭快照句柄
  41. CloseHandle(hSnapshot);
  42. return pids;
  43. }
  44. void addToStartup()
  45. {
  46. QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
  47. QSettings::NativeFormat);
  48. QString appPath = QCoreApplication::applicationFilePath(); // 获取应用程序路径
  49. settings.setValue("BaseMainApp", appPath); // 将应用程序路径添加到注册表
  50. }
  51. void setAutoStart(bool enable)
  52. {
  53. QString appPath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
  54. QString taskName = "YourAppName"; // 替换为你的应用程序名称
  55. if (enable) {
  56. QString tempPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
  57. QString xmlFilePath = QDir::toNativeSeparators(tempPath + "/task.xml");
  58. QFile xmlFile(xmlFilePath);
  59. if (xmlFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
  60. QString xmlContent = QString(R"(<?xml version="1.0" encoding="UTF-16"?>
  61. <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  62. <RegistrationInfo>
  63. <Description>Auto start task for %1</Description>
  64. </RegistrationInfo>
  65. <Triggers>
  66. <LogonTrigger>
  67. <Enabled>true</Enabled>
  68. <Delay>PT10S</Delay>
  69. </LogonTrigger>
  70. </Triggers>
  71. <Principals>
  72. <Principal id="Author">
  73. <GroupId>S-1-5-32-544</GroupId>
  74. <RunLevel>HighestAvailable</RunLevel>
  75. </Principal>
  76. </Principals>
  77. <Settings>
  78. <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
  79. <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
  80. <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
  81. <AllowHardTerminate>true</AllowHardTerminate>
  82. <StartWhenAvailable>true</StartWhenAvailable>
  83. <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
  84. <IdleSettings>
  85. <StopOnIdleEnd>false</StopOnIdleEnd>
  86. <RestartOnIdle>false</RestartOnIdle>
  87. </IdleSettings>
  88. <AllowStartOnDemand>true</AllowStartOnDemand>
  89. <Enabled>true</Enabled>
  90. <Hidden>false</Hidden>
  91. <RunOnlyIfIdle>false</RunOnlyIfIdle>
  92. <WakeToRun>false</WakeToRun>
  93. <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
  94. <Priority>7</Priority>
  95. </Settings>
  96. <Actions Context="Author">
  97. <Exec>
  98. <Command>%2</Command>
  99. </Exec>
  100. </Actions>
  101. </Task>)")
  102. .arg(taskName, appPath);
  103. // 将内容写入为 UTF-16LE 格式
  104. QTextStream out(&xmlFile);
  105. out.setCodec("UTF-16LE");
  106. out.setGenerateByteOrderMark(true);
  107. out << xmlContent;
  108. xmlFile.close();
  109. QStringList arguments;
  110. arguments << "/c"
  111. << "schtasks"
  112. << "/create"
  113. << "/tn" << taskName << "/xml" << xmlFilePath << "/f";
  114. qDebug() << "Executing command with arguments:" << arguments;
  115. QProcess process;
  116. process.start("cmd.exe", arguments);
  117. process.waitForFinished();
  118. QString error = QString::fromLocal8Bit(process.readAllStandardError());
  119. QString output = QString::fromLocal8Bit(process.readAllStandardOutput());
  120. if (!error.isEmpty()) {
  121. qDebug() << "Error output:" << error;
  122. }
  123. if (!output.isEmpty()) {
  124. qDebug() << "Standard output:" << output;
  125. }
  126. xmlFile.remove();
  127. }
  128. } else {
  129. QStringList arguments;
  130. arguments << "/c" << "schtasks" << "/delete" << "/tn" << taskName << "/f";
  131. QProcess::execute("cmd.exe", arguments);
  132. }
  133. }
  134. void redirectOutputToLogFile()
  135. {
  136. // 重定向 qDebug、qWarning 和 qCritical 的输出
  137. qInstallMessageHandler([](QtMsgType type,
  138. const QMessageLogContext &context,
  139. const QString &msg) { // 获取当前日期
  140. Q_UNUSED(context)
  141. if (type == QtWarningMsg) {
  142. return;
  143. }
  144. QString dateString = QDate::currentDate().toString("yyyy-MM-dd");
  145. // 获取应用程序的日志文件路径
  146. QString logFileName = "./log/" + dateString + "_base.txt";
  147. // 创建 QFile 对象
  148. QFile logFile(logFileName);
  149. // 打开文件进行写入,如果文件不存在则创建
  150. if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
  151. qWarning() << "Unable to open log file for writing:" << logFile.errorString();
  152. return;
  153. }
  154. QTextStream out(&logFile);
  155. QString timeString = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
  156. switch (type) {
  157. case QtDebugMsg:
  158. out << timeString << " [DEBUG] " << msg << "\n";
  159. break;
  160. case QtWarningMsg:
  161. out << timeString << " [WARNING] " << msg << "\n";
  162. break;
  163. case QtCriticalMsg:
  164. out << timeString << " [CRITICAL] " << msg << "\n";
  165. break;
  166. case QtFatalMsg:
  167. out << timeString << " [FATAL] " << msg << "\n";
  168. // abort(); // 终止程序
  169. case QtInfoMsg:
  170. break;
  171. }
  172. logFile.close();
  173. });
  174. }
  175. int main(int argc, char *argv[])
  176. {
  177. // QApplication a(argc, argv);
  178. SharedTools::QtSingleApplication a("BaseMainApp", argc, argv);
  179. QDir dir;
  180. dir.mkdir("log"); // 创建日志目录
  181. addToStartup(); // 开机启动
  182. #ifdef QT_DEBUG
  183. setAutoStart(false);
  184. #else
  185. setAutoStart(true);
  186. redirectOutputToLogFile(); // 日志
  187. #endif
  188. a.setOrganizationName("BaseMainApp");
  189. a.setApplicationName("BaseMain");
  190. a.setApplicationVersion("1.1.5");
  191. a.setQuitOnLastWindowClosed(false);
  192. QCommandLineParser parser;
  193. parser.addHelpOption();
  194. parser.addVersionOption();
  195. QCommandLineOption debugOption("debug", "Enable debug mode");
  196. parser.addOption(debugOption);
  197. parser.process(a);
  198. qDebug() << QCoreApplication::organizationName() << QCoreApplication::applicationName()
  199. << QCoreApplication::applicationFilePath();
  200. QString appFilePath = QCoreApplication::applicationFilePath();
  201. QString appName = QFileInfo(appFilePath).fileName();
  202. qDebug() << "Application Path:" << appFilePath;
  203. qDebug() << "Application Name:" << appName;
  204. if (a.isRunning()) {
  205. a.sendMessage("", 1000);
  206. return 0;
  207. }
  208. // 多重判断 防止异常
  209. HANDLE hMutex = CreateMutex(NULL, TRUE, L"Global\\Unique_BaseMainApp");
  210. // 检查是否已经有实例在运行
  211. if (hMutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
  212. return 0; // 退出当前程序,避免多个实例运行
  213. }
  214. // 多重判断
  215. auto pids = GetProcessIDsByName(appName.toStdWString().c_str());
  216. if (pids.size() > 1) {
  217. qDebug() << appName << " size:" << pids.size();
  218. }
  219. qSetMessagePattern("[%{time process}][%{line}]"
  220. "%{if-debug}D%{endif}"
  221. "%{if-info}I%{endif}"
  222. "%{if-warning}W%{endif}"
  223. "%{if-critical}C%{endif}"
  224. "%{if-fatal}F%{endif}:"
  225. "%{message} %{file}");
  226. QTranslator translator;
  227. const QStringList uiLanguages = QLocale::system().uiLanguages();
  228. for (const QString &locale : uiLanguages) {
  229. const QString baseName = "basemain_" + QLocale(locale).name();
  230. if (translator.load(":/i18n/" + baseName)) {
  231. a.installTranslator(&translator);
  232. break;
  233. }
  234. }
  235. WebSocketClient::getInstance();
  236. HostThread host;
  237. UpdaterThread thread;
  238. ProcessThread Process;
  239. MessageQueue messageQueue;
  240. QObject::connect(&Process, &ProcessThread::messageBox, &messageQueue, &MessageQueue::addMessage);
  241. QObject::connect(&Process, &ProcessThread::finished, &Process, &QObject::deleteLater);
  242. // thread.start();
  243. // Process.start();
  244. // host.start();
  245. return a.exec();
  246. }