Я пытаюсь поймать сбой приложения и показать пользователю экран для подтверждения отчета о сбое. Идея такова: когда происходит сбой, я собираюсь загрузить QML для особого случая с описанием сбоя и кнопкой для его отправки. Но я не могу перезагрузить уже существующий файл main.qml
, функция QApplication::exit()
просто не выходит из основного цикла событий, поэтому экран «crash.qml» никогда не показывается пользователю.
Вот минимальный рабочий пример для воспроизведения моей проблемы:
/// main.cpp
#include <QDebug>
#include <QObject>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <setjmp.h>
#include <signal.h>
#include "cpp.h"
CPP cpp_obj;
sigjmp_buf main_entry;
void signal_handler(int signum) {
signal(SIGSEGV, SIG_DFL); // clear signal handler as we don't need it anymore
qDebug() << "got crash";
qGuiApp->exit(1);
longjmp(main_entry, 1);
}
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQmlContext* ctext = engine.rootContext();
ctext->setContextProperty("cpp_obj", &cpp_obj);
if (engine.rootObjects().isEmpty())
return -1;
signal(SIGSEGV, signal_handler);
int retcode;
if (setjmp(main_entry) == 0) {
qDebug() << "app starting normal";
retcode=app.exec();
qDebug() << "app returned from normal call, retcode=" << retcode;
} else {
qDebug() << "loading crash qml file";
engine.load(QUrl(QStringLiteral("qrc:/crash.qml")));
qDebug() << "entering crash's main event loop";
retcode=app.exec();
}
qDebug() << "exiting app at the end of the main(), retcode=" << retcode;
return retcode;
}
//cpp.h
#ifndef CPP_H
#define CPP_H
#include <QObject>
class CPP : public QObject
{
Q_OBJECT
public:
explicit CPP(QObject *parent = nullptr);
Q_INVOKABLE void crash_app();
signals:
void app_crashed(QString failure_description);
};
#endif // CPP_H
/// cpp.cpp
#include "cpp.h"
CPP::CPP(QObject *parent) : QObject(parent)
{
}
void CPP::crash_app() {
char *ptr=nullptr;
*ptr='A';
}
///main.qml
import QtQuick 2.11
import QtQuick.Controls 2.4
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("The App runs fine")
Button {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "Simulate Crash"
onClicked: cpp_obj.crash_app()
}
}
///crash.qml
import QtQuick 2.11
import QtQuick.Controls 2.4
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Crash Report")
Label {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "The app has failed"
}
Button {
text: "Submit Crash Report"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
onClicked: {
// TODO: send crash report via UDP
}
}
}
Когда я запускаю его, вот что я получаю на консоли:
QML debugging is enabled. Only use this in a safe environment.
app starting normal
got crash
loading crash qml file
entering crash's main event loop
QCoreApplication::exec: The event loop is already running
exiting app at the end of the main(), retcode= -1
Если есть другой способ достичь того, что мне нужно, я был бы признателен за ваши идеи