问题描述
Qt 应用程序在异常崩溃时自动重启,有没有比较标准"的设计?
Is there any relatively "standard" design to auto restart a Qt application program, when it crashes abnormally?
特定于 Windows,我必须使用任何 Windows 服务吗?
或者如果我必须单独编写另一个程序,那该怎么做?
Specific to Windows, do I have to use any windows service?
Or if I have to write another program separately, then how to do that?
推荐答案
以下是您如何使用可充当监视器或业务逻辑的单个应用程序来完成此操作.它类似于 Jon Harper 的回答,除了代码,而不是散文:)
Here's how you might do it using a single application that can act either as a monitor or as business logic. It's akin to Jon Harper's answer, except in code, not prose :)
监视器不应实例化
QApplication
或QGuiApplication
:它没有 UI.否则,在某些平台(如OS X、Win 10)上会出现冗余运行进程指示器.
The monitor should not instantiate a
QApplication
norQGuiApplication
: it has no UI. Otherwise, redundant running process indicators will appear on some platforms (i.e. OS X, Win 10).
监视器/业务逻辑选择是通过在被调用进程中设置环境变量来实现的.
The monitor/business logic selection is achieved via setting an environment variable in the called process.
通过命令行参数传递监视器/业务逻辑选择是有问题的,因为需要过滤掉命令行开关——在不遇到极端情况的情况下进行移植是很棘手的.
Passing the monitor/business logic selection via command line arguments is problematic, as the command line switch would need to be filtered out -- doing that portably without running into corner cases is tricky.
监控进程转发业务逻辑进程的控制台I/O,以及返回码.
The monitor process forwards the console I/O of the business logic process, as well as the return code.
// https://github.com/KubaO/stackoverflown/tree/master/questions/appmonitor-37524491
#include <QtWidgets>
#include <cstdlib>
#if defined(Q_OS_WIN32)
#include <windows.h>
#else
static void DebugBreak() { abort(); }
#endif
static int businessLogicMain(int &argc, char **argv) {
QApplication app{argc, argv};
qDebug() << __FUNCTION__ << app.arguments();
QWidget w;
QHBoxLayout layout{&w};
QPushButton crash{"Crash"}; // purposefully crash for testing
QPushButton quit{"Quit"}; // graceful exit, which doesn't need restart
layout.addWidget(&crash);
layout.addWidget(&quit);
w.show();
QObject::connect(&crash, &QPushButton::clicked, DebugBreak);
QObject::connect(&quit, &QPushButton::clicked, &QCoreApplication::quit);
return app.exec();
}
static char const kRunLogic[] = "run__business__logic";
static char const kRunLogicValue[] = "run__business__logic";
#if defined(Q_OS_WIN32)
static QString getWindowsCommandLineArguments() {
const wchar_t *args = GetCommandLine();
bool oddBackslash = false, quoted = false, whitespace = false;
// skip the executable name according to Windows command line parsing rules
while (auto c = *args) {
if (c == L'\\')
oddBackslash ^= 1;
else if (c == L'"')
quoted ^= !oddBackslash;
else if (c == L' ' || c == L'\t')
whitespace = !quoted;
else if (whitespace)
break;
else
oddBackslash = false;
args++;
}
return QString::fromRawData(reinterpret_cast<const QChar*>(args), lstrlen(args));
}
#endif
static int monitorMain(int &argc, char **argv) {
#if !defined(Q_OS_WIN32)
QStringList args;
args.reserve(argc-1);
for (int i = 1; i < argc; ++i)
args << QString::fromLocal8Bit(argv[i]);
#endif
QCoreApplication app{argc, argv};
QProcess proc;
auto onFinished = [&](int retcode, QProcess::ExitStatus status) {
qDebug() << status;
if (status == QProcess::CrashExit)
proc.start(); // restart the app if the app crashed
else
app.exit(retcode); // no restart required
};
QObject::connect(&proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), onFinished);
auto env = QProcessEnvironment::systemEnvironment();
env.insert(kRunLogic, kRunLogicValue);
proc.setProgram(app.applicationFilePath()); // logic and monitor are the same executable
#if defined(Q_OS_WIN32)
SetErrorMode(SEM_NOGPFAULTERRORBOX); // disable Windows error reporting
proc.setNativeArguments(getWindowsCommandLineArguments()); // pass command line arguments natively
env.insert("QT_LOGGING_TO_CONSOLE", "1"); // ensure that the debug output gets passed along
#else
proc.setArguments(args);
#endif
proc.setProcessEnvironment(env);
proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.start();
return app.exec();
}
int main(int argc, char **argv) {
if (qgetenv(kRunLogic) != kRunLogicValue)
return monitorMain(argc, argv);
else
return qunsetenv(kRunLogic), businessLogicMain(argc, argv);
}
这篇关于如何在同一个程序中崩溃时自动重启 Qt 应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!