Qt handle process termination - c++

I have a Qt application that starts another application. I want to receive a signal, if the child application is terminated externally.
The code is:
CaptureApp::CaptureApp(int& argc, char** argv): QApplication(argc, argv)
{
launchDaemon();
}
void CaptureApp::launchDaemon()
{
QString command = "daemon";
QStringList arguments;
arguments << "somearg";
process = new QProcess(this);
process->start(command, arguments);
connect(process,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(daemonDied(QProcess::ProcessState)));
connect(process,SIGNAL(finished(int)),this,SLOT(daemonDied(int)));
}
void CaptureApp::daemonDied(QProcess::ProcessState state)
{
std::cout << "DAEMON DIED" << std::endl;
}
void CaptureApp::daemonDied(int code)
{
std::cout << "DAEMON DIED" << std::endl;
}
But no message appears when I kill child process. What am I doing wrong?

I tried your example inherriting from QApplication, but in the first place it gave me this error:
QObject::connect: No such slot QApplication::daemonDied(QProcess::ProcessState)
QObject::connect: No such slot QApplication::daemonDied(int)
I then added Q_OBJECT to the class definition and it connected the signals/slots, but when I killed the process it gave the following error:
ICE default IO error handler doing an exit(), pid = 27773, errno = 4
When I however changed the class to inherit from QObject instead of QApplication it did work. So having the main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CaptureApp captureApp(argc,argv);
return a.exec();
}
As commented by jbm, some processes stay attached, while others are not. I tried first gedit and it received a signal directly after starting indicating the processes had finished. Using vim however it did keep running and I was able to kill it externally.

Related

How to start a thread that doesn't close on application quit? (Qt C++)

I'm making an application for Mac OS X in Qt, and wanted to spawn a thread that doesn't close on application close.
Is this possible? If so, how? I don't want the process to be stopped if a user force quits the application.
Thanks in advance.
Note: If this is not possible, is there any way I can make this happen? (Maybe with calling a command in bash?)
it's possible to achieve your goal by initiating a new process via QProcess::startDetached, as per documents http://doc.qt.io/qt-4.8/qprocess.html#startDetached
Starts the program program with the arguments arguments in a new process, and detaches from it. Returns true on success; otherwise returns false. If the calling process exits, the detached process will continue to live.
Unix: The started process will run in its own session and act like a daemon.
Edit:
Here is an example for MacOS
// run start script
QString scriptPath = "path-to-start-script/start.sh" ;
QString cmd = "open -a " + scriptPath;
QProcess::startDetached(cmd);
When you terminate a process, all threads within that process die - the process is the thread "container". If you want to spawn something that lives on beyond your current process, then spawn a new independant process.
If your user force-quits the application, that usually means that they want to control the energy or resource expenditure on their system. Thinking that you know better than the user would be rather in the user's face. Don't anger your users :)
All you really want is:
For the process to survive quitting it through normal means (pressing ⌘-Q, selecting Quit from the menu, closing the last window, etc.).
For the dock icon to disappear after the GUI has been quit, as is the normal and expected behavior.
For a cleanup code to run after the GUI has vanished.
To that effect, you only need to hide the dock icon/menubar and then perform the cleanup:
main.mm
// https://github.com/KubaO/stackoverflown/tree/master/questions/hidedock-39378276
#include <QtWidgets>
#include <AppKit/AppKit.h>
void hideDockIcon() {
[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited];
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QLabel label{"Quit Me"};
label.setMinimumSize(200, 100);
label.show();
int rc = app.exec();
hideDockIcon();
qDebug() << "cleaning up";
QThread::sleep(5);
qDebug() << "cleanup finished";
return rc;
}
hidedock-39378276.pro
QT = widgets
CONFIG += c++11
TARGET = hidedock-39378276
TEMPLATE = app
OBJECTIVE_SOURCES += main.mm
LIBS += -framework AppKit
If u mean closing of Gui window by "Application Close" then it can be done easily...
#include "MainWindow.h"
#include <QApplication>
//////////////////////////////////////
#include <thread>
struct blabla {
std::thread th;
blabla():th([]{
// body of your thread
}) {}
~blabla(){
if(th.joinable())
th.join();
}
} singleton_obj;
/////////////////////////////////////
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Now the applicaton window will quit but the daemon thread will run n background...
Enjoy

How to auto restart a Qt application when it crashes, within the same program?

Is there any relatively "standard" design to auto restart a Qt application program, when it crashes abnormally?
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?
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 :)
Of Note
The monitor should not instantiate a QApplication nor QGuiApplication: 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.
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);
}
If an application crashes, it's done.
Your monitor idea is a good one, and can be achieved using QProcess. Use the "monitor" to bootstrap your actual application. To do this, implement a monitoring object with a QProcess member. In pseudocode:
class MonitorObject : public QObject
{
...
public Q_SLOTS:
void onStarted();
void onFinished(int, QProcess::ExitStatus);
...
private:
QProcess m_process;
}
Then in main:
Create a QCoreApplication and a monitoring object on the stack.
Send a queued signal to your monitor object so it knows when the main event loop starts. You can achieve this using QMetaObject::invoke with a Qt::QueuedConnection:
int main(...)
{
QCoreApplication app;
MonitorObject monitor;
... // other initialization code here
QMetaObject::invoke(&monitor, "onStarted", Qt::QueuedConnection);
return app.exec();
}
And in your MonitorObject:
Connect QProcess's finished signal to onFinished.
When MonitorObject::onStarted is called, start the process.
When the QProcess::finished signal fires, either restart the offending program or exit, depending on the exitCode argument in the emitted signal.
I don't know of any standard Qt method for restarting apps when they crash. But there is a nice class available which makes writing a supervisor/monitor class very easy. It is called QProcess.
You can start the process like this:
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);
}
Then when the timer expires (every second - or whatever)
void monitorClass::TimerExpired(void)
{
switch (mp_Process->state())
{
default:
case QProcess::NotRunning:
{
qDebug("Process has stopped un-expectedly\n");
// Tell the supervisor that the process has terminated
// restart the process
startProcess("c:\mytestapp.exe param1 param2"); // just an example
break;
}
case QProcess::Starting:
case QProcess::Running:
{
qDebug("Process is running ok\n");
break;
}
}
}
Note
This is really pseudo code, its not a compilable example - it is just to show you roughly the how easy it is to do this with QProcess...

maximizing the already running instance of a single instance app in qt

I have made an application to run only single instance using shared memory in qt.My code looks like this
int main(int argc, char *argv[])
{
QSharedMemory sharedMemory;
sharedMemory.setKey("4da7b8a28a378e7fa9004e7a95cf257f");
if(!sharedMemory.create(1))
{
return 1; // Exit already a process running
}
QApplication a(argc, argv);
Encoder *encoder = Encoder::instance();
encoder->show();
return a.exec();
}
Now, I need to show the already running instance to the user (Maximize the window), when they try to run another instance. How can I achieve this?
There is an easy setup using QtSingleApplication instead :
QtSingleApplication app("myapp",argc, argv);
if (app.isRunning()) {
QListIterator<QString> it(messagestosend);
QString rep("Another instance is running, so I will exit.");
bool sentok = false;
while(it.hasNext()){
sentok = app.sendMessage(it.next(),1000);
if(!sentok)
break;
}
rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen.";
return 0;
}
To receive this message you should listen with your desired slot to the signal
void QtSingleApplication::messageReceived(const QString&)

Send a Quit message to Qt app with event loop from another process in Windows

I've created a server using Qt and QTcpServer. It runs in the background and doesn't show any windows, but it uses an event loop.
My main.cpp looks like this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyServer theServer;
return a.exec();
}
How do I notify my server to close, without resorting to TerminateProcess()? I'm fine with a Windows-only solution, so I can use WINAPI functions if needed.
Depending upon what the server is for, as you're using TCPServer, you could send it a message to tell it to quit, though you may want to authenticate who is sending that message.
Alternatively, have a controller application on the same machine that can talk to the server via a named pipe, which you can use to tell it to quit.
I just implemented it using QLocalServer. It turned out to be very easy:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
static const char *quitSignalName = "My Service Quit Signal";
const QStringList &args = a.arguments();
if (args.size() == 2 && args[1] == "--shutdown") {
// Connect to the named pipe to notify the service it needs
// to quit. The QLocalServer will then end the event loop.
QLocalSocket quitSignal;
quitSignal.connectToServer(quitSignalName);
quitSignal.waitForConnected();
return 0;
}
// Listen for a quit signal, we connect the newConnection() signal
// directly to QApplication::quit().
QLocalServer quitSignalWatcher;
QObject::connect(&quitSignalWatcher, SIGNAL(newConnection()), &a, SLOT(quit()));
quitSignalWatcher.listen(quitSignalName);
MyServer theServer;
Q_UNUSED(theServer);
return a.exec();
}

QObject::moveToThread: Widgets cannot be moved to a new thread

My IDE Qt 5.0.1, platform Linux
i have a problem about set widgets to window.(My opinion)
this is my main.cpp->
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread cThread;
MainWindow w;
w.doSetup(cThread);
w.moveToThread(&cThread);
cThread.start();
if(cThread.isRunning())
{
qDebug() << " Thread is Running...";
}
w.show();
return a.exec();
}
this is doSetup() method->
void MainWindow::doSetup(QThread &mainThread)
{
QObject::connect(&mainThread, &QThread::started, this, &MainWindow::activeLoopMainC);
}
i checked my signal-slot mechanism and it works.
slot method->
void MainWindow::activeLoopMainC()
{
qDebug() << " Signal-Slot structure working successfully..";
mainThreadProc((void*)(instAddr));
}
i call a function from my main.c by this slot method.
In debugging there is no problem about working codes. But my window is blank. there is only frame.
i receive an error message: QObject::moveToThread: Widgets cannot be moved to a new thread
How can i solve this problem?
Thank you in advance for your answers.
You can't move widgets into another thread - in order to keep user interface responsive, Qt needs to do all GUI work inside main thread.
If you have background work to do, then move background worker to other thread, and not the user interface.