C++ 当Qt应用程序崩溃时,如何在同一程序中自动重启?

C++ 当Qt应用程序崩溃时,如何在同一程序中自动重启?,c++,windows,qt,process,restart,C++,Windows,Qt,Process,Restart,当Qt应用程序异常崩溃时,是否有相对“标准”的设计来自动重启它 特定于Windows,我必须使用任何Windows服务吗? 或者,如果我必须单独编写另一个程序,那么如何才能做到这一点?我不知道有什么标准的Qt方法可以在应用程序崩溃时重新启动它们。但是有一个很好的类,它使得编写一个主管/监控类非常容易。它被称为QProcess 您可以按如下方式启动此过程: monitorClass::startProcess(QString commandLine) // e.g. "c:\mytestapp.e

当Qt应用程序异常崩溃时,是否有相对“标准”的设计来自动重启它

特定于Windows,我必须使用任何Windows服务吗?

或者,如果我必须单独编写另一个程序,那么如何才能做到这一点?

我不知道有什么标准的Qt方法可以在应用程序崩溃时重新启动它们。但是有一个很好的类,它使得编写一个主管/监控类非常容易。它被称为QProcess

您可以按如下方式启动此过程:

monitorClass::startProcess(QString commandLine) // e.g. "c:\mytestapp.exe param1 param2"
{
    mp_Process = new QProcess(this);
    mp_Process->start(commandLine);
    mp_Process->waitForStarted();

    // Start a timer
    mp_Timer->start(1000);
}
然后,当计时器过期时(每秒钟一次,或其他任何时间)

注意


这实际上是伪代码,它不是一个可编译的示例-它只是向您大致展示了使用QProcess执行此操作有多容易…

如果应用程序崩溃,它就完成了

您的监视器想法很好,可以通过使用来实现。使用“监视器”引导实际应用程序。为此,使用
QProcess
成员实现一个监控对象。在伪代码中:

 class MonitorObject : public QObject
 {
     ...
 public Q_SLOTS:
     void onStarted();
     void onFinished(int, QProcess::ExitStatus);
     ...
 private:
     QProcess m_process;
 }
然后在
main
中:

  • 在堆栈上创建一个
    QCoreApplication
    和一个监控对象
  • 向监视器对象发送排队信号,以便它知道主事件循环何时启动。您可以通过使用
    Qt::QueuedConnection

    int main(...)
    {
        QCoreApplication app;
        MonitorObject monitor;
    
        ... // other initialization code here
    
        QMetaObject::invoke(&monitor, "onStarted", Qt::QueuedConnection);
        return app.exec();
    }
    
在您的
监视器对象中

  • QProcess
    finished
    信号连接到
    onFinished
  • 调用
    MonitorObject::onStarted
    时,启动该过程
  • 当触发
    QProcess::finished
    信号时,根据发出的信号中的
    exitCode
    参数,重新启动有问题的程序或退出

以下是使用单个应用程序(既可以用作监视器,也可以用作业务逻辑)执行此操作的方法。这类似于乔恩·哈珀的答案,除了代码,而不是散文:)

值得注意
  • 监视器不应实例化
    QApplication
    QGuiApplication
    :它没有UI。否则,在某些平台(即OS X、Win 10)上会出现冗余的运行过程指示器

  • 监视器/业务逻辑选择是通过在被调用的流程中设置环境变量来实现的

  • 通过命令行参数传递监视器/业务逻辑选择是有问题的,因为命令行开关需要被过滤掉——这样做既可移植又不会遇到麻烦

  • 监视进程转发业务逻辑进程的控制台I/O以及返回代码

  • //https://github.com/KubaO/stackoverflown/tree/master/questions/appmonitor-37524491
    #包括
    #包括
    #如果已定义(Q_OS_WIN32)
    #包括
    #否则
    静态void DebugBreak(){abort();}
    #恩迪夫
    静态int-businessLogicMain(int&argc,字符**argv){
    QApplication app{argc,argv};
    
    qDebug()您可以将应用程序设置为windows服务,并将“恢复”属性(当服务失败时)设置为“重新启动服务”。若要在Qt上创建windows服务,您可以尝试此项目:如果可以,我会为“代码,而不是散文”额外加1.:-)
    int main(...)
    {
        QCoreApplication app;
        MonitorObject monitor;
    
        ... // other initialization code here
    
        QMetaObject::invoke(&monitor, "onStarted", Qt::QueuedConnection);
        return app.exec();
    }
    
    // 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);
    }