main.cpp 9.0 KB

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