How to manage single instance of a Qt app on crash? - c++

I want to execute my application as single instance, currently I am using QSharedMemory and working fine. I am using Qt5.2.1 on Ubuntu 12.04.
Below is my test code:
QApplication a(argc, argv);
a.processEvents();
const char* MEM_KEY = "56";
QSharedMemory sharedMem(MEM_KEY);
if( !sharedMem.create( 512, QSharedMemory::ReadWrite) )
{
QMessageBox msgBox;
msgBox.setText( QObject::tr("Can't start more than one instance of the application.") );
msgBox.setIcon( QMessageBox::Critical );
msgBox.exec();
exit(0);
}
MainWindow w;
w.show();
int p=0;
//p=p/0; // create exception here
return a.exec();
But the if makes the application crash(as shown in above code). If I start the application again, it shows Can't start more than one instance of the application, which means the previous instance is still there even if it has crashed. It should not happen in my case.
How can I restart my application in such a situation?
Edit:
Actually my original project contains lot of source files (the above one just made for testing). I want to implement it on my original project with editing least source file, if possible only by editing main.cpp

You can use a QSetting:
int main(int argc, char *argv[])
{
QSettings settings;
QApplication a(argc, argv);
if(!settings.exitedNormaly()) {
// In case of crash
}
// set the flag to false
settings.setExitedNormaly(false);
MainWindow w(&settings);
w.processArg(argc, argv);
w.show();
int result = a.exec();
settings.setExitedNormaly(result == 0);
return result;
}
Combined with your shared memory, you'll be able to unlock the block in case of application crash.

for linux:
//----------------------------------
QProcess *m_prSystemCall;
m_prSystemCall = new QProcess();
QString Commnd = "pgrep " + qApp->applicationDisplayName();
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
QString output(m_prSystemCall->readAllStandardOutput());
QStringList AppList = output.split("\n", QString::SkipEmptyParts);
qDebug() <<"pgrep out:"<<AppList;
for(int i=0;i<AppList.size()-1;i++)
{
Commnd = "kill " + AppList.at(i);
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
}
//-------------------------------------------------------
and for Windows:
#include <tlhelp32.h>
#include <comdef.h>
QString pName = qApp->applicationDisplayName();
pName += ".exe";
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
DWORD myPID = GetCurrentProcessId();
while (Process32Next(snapshot, &entry) == TRUE)
{
const WCHAR* wc = entry.szExeFile ;
_bstr_t b(wc);
const char* c = b;
if (stricmp(c, pName.toStdString().c_str()) == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
qDebug() <<"myPID: "<< myPID << "entry.th32ProcessID" << entry.th32ProcessID;
if(myPID != entry.th32ProcessID)
TerminateProcess(hProcess,0);
QThread::msleep(10);
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);

Related

How to embed one qApplication's GUI into another qApplication's mainWindow?

There are two qApplications A & B, they can be executed separately with their own main window.
I would like to achieve the following:
1) //Open Application B.
//Inside App B's code
QProcess* proA = new QProcss();
proA->start(A.exe) //Under Windows7
2) //Instead of showing app A in a separate window.
//I would like to show it as a widget of app B's main window.
Sort of like google chrome. A similar post here:QT How to embed an application into QT widget talked about the similar problem. But it involves implement your own window management system. Is there simpler solutions as both my app are Qt's qApp and both uses QWindow.
It's definitely possible if the two QApplications are in different processed.
Create two process each with it's QApplication and QWidget
From one process, find the winId of the other processe's QWidget and reparent it to your own widget.
To manage the widget from the other process reparented to yours, you may use qtwinmigrate. Originally this was meant to embed a MFC widget (with its own CWinApp) in a Qt widget, but it can also help embedding a QWidget from a separate process.
Here is a piece of working code:
Child process:
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>
#include <QApplication>
#include <sstream>
int main(int argc, char **argv)
{
QApplication app(argc,argv);
QWidget widget;
widget.setWindowTitle( "CHILD WINDOW" );
std::stringstream str;
str << "QWidget ID: " << widget.winId() << std::endl;
str << "Process Name: " << argv[0];
Qt::WindowFlags flags = widget.windowFlags();
flags |= Qt::FramelessWindowHint;
flags |= Qt::MSWindowsFixedSizeDialogHint;
flags |= Qt::SubWindow;
widget.setWindowFlags( flags );
widget.setLayout(new QVBoxLayout(&widget));
QLabel label;
widget.layout()->addWidget(&label);
label.setText(str.str().c_str());
widget.setStyleSheet( "background: red" );
widget.show();
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(&label, &e);
app.processEvents();
return app.exec();
}
Parent process:
#include <QMainWindow>
#include <QApplication>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QLabel>
#include <QProcess>
#include "windows.h"
#include "qtwinmigrate5/qwinhost.h"
#include <iostream>
#include <sstream>
/* The EnumChildProc callback */
static HWND hWndHandle = NULL;
static qint64 childProcessID = 0;
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
DWORD dwProcessID = 0;
if (GetWindowThreadProcessId(hwnd, &dwProcessID) &&
dwProcessID == childProcessID )
{
char strTemp[256] = "";
GetWindowText(hwnd, strTemp, 256);
std::string str = strTemp;
if (str == "CHILD WINDOW") // sanity check
hWndHandle = hwnd;
}
return ( hWndHandle == NULL ); // must return TRUE; If return is FALSE it stops the recursion
}
void* GetChildWindowHandle( qint64 pid )
{
hWndHandle = NULL;
childProcessID = pid;
EnumWindows(EnumChildProc, 0);
return hWndHandle;
}
int main(int argc, char **argv)
{
QApplication app(argc,argv);
QMainWindow wnd;
wnd.setWindowTitle("That's the parent window!");
// Create child process:
QProcess process;
process.start("test_3rdparty_inprg_qtwinmigrate_child.exe");
if (process.state() != QProcess::Running)
{
QMessageBox::critical(NULL, "ERROR", "Unable to create child process");
return 1;
}
// Create qtwinmigrate widget container:
QWinHost* host = new QWinHost( &wnd );
// Get child process wiindow handle
HWND hChildWnd = NULL;
int timeout = 20;
while ((hChildWnd = (HWND)GetChildWindowHandle(process.processId())) == NULL)
{
// let child process more time to create and show its widget....
Sleep(200);
--timeout;
if (timeout == 0)
break;
}
int res = 1;
if (hChildWnd != NULL)
{
// attach child window handle to qtwinmigrate widget container
host->setWindow(hChildWnd);
char strTemp[256] = "";
GetWindowText(hChildWnd, strTemp, 256);
QWidget centralWidget(&wnd);
wnd.setCentralWidget(&centralWidget);
QVBoxLayout* layout = new QVBoxLayout(&centralWidget);
std::stringstream str;
str << "Attached data window " << std::showbase << std::hex << hChildWnd << std::endl;
str << "Window title: " << strTemp << std::endl;
str << "Widget below runs in a separate process:" << std::endl;
layout->addWidget( new QLabel( str.str().c_str(), &centralWidget ) );
layout->addWidget(host);
wnd.resize(400, 200);
wnd.show();
res = app.exec();
}
else
{
QMessageBox::critical(NULL, "ERROR", "Unable to find child process widget");
}
// kill child process
process.kill();
return res;
}
1- Compile child process into an executable named test_3rdparty_inprg_qtwinmigrate_child.exe.
2- Compile parent process into an executable
3- Run parent process, this one will start the child process, find it's top level widget window handle and insert it within its own QMainWindow as a child. When done, it will kill the child process.
As a end user, it's hard to tell the widgets are not part of the same process, they are perfectly embedded (the red part of the widget comes from the child process):
well, that's the idea of the whole QWidget approach: Everything that can be put in a container can be part of another application.
However, putting a complete, unmodified Qt application into another one will not be possible: There can only be one QApplication instance, and only one global event loop.

Communicate with two instances of Qt program

I used in my Qt program code to avoid opening second instance:
#include "mainwindow.h"
#include <QApplication>
#include <QSharedMemory>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
const char* MEM_KEY = "42";
QSharedMemory sharedMem(MEM_KEY);
if (sharedMem.create(1024))
{
qDebug() << "Create shared memory";
}
else
{
if (sharedMem.error() == QSharedMemory::AlreadyExists)
{
qWarning() << "Already create. Exiting process";
return 1;
}
}
MainWindow w;
w.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);
w.show();
return a.exec();
It works (this code block opening second instance of my aplication [it is automatically close]), but I want to send an message or signal from opened for a moment second instance to first instance to perform for ex. maximalize window of first instance. Could you tell me how to do this simply?
You can use QtSingleApplication for this purpose. For example:
int main(int argc, char *argv[])
{
QtSingleApplication a(argc, argv);
if (a.isRunning())
{
a.sendMessage("42");
qWarning() << "Already create. Exiting process";
return 1;
}
MainWindow w;
a.setActivationWindow(&w);
QObject::connect(&a, SIGNAL(messageReceived(QString))
, &w, SLOT(onMessageReceived(QString)));
w.show();
int ret = a.exec();
QObject::disconnect(&a, 0, &w, 0);
return ret;
}
...
void MainWindow::onMessageReceived(const QString &message)
{
// Do stuff
}
You are looking for IPC (inter process communication) and sadly, i don't think there is a portable way of doing this, except for creating a socket and listening on 127.0.0.1. But if you are on unix i do recommend using qdbus. That is what all the cool linux programs are doing ;)
On windows there is i believe something similar. (But this is all not built into qt.) You can find the handle of your window (HWND) and use sendmessage().
to send a custom message you'll have to declare your own WM_SECONDINSTANCE (or something similar) by:
#define WM_SECONDINSTANCE WM_USER
#define WM_SOMEOTHERMESSAGE WM_USER+1
or use an enum (i'm lazy).
This tells your existing instance that another instance has been opened. To handle it in qt have a look at this.
To find the HWND, i would just put it int your shared memory from your first instance.
(My windows-knowledge is a bit rusty, so sorry for any errors)

Unable to open file with qt app on mac

I am trying to associate custom files with an osx app. I have a plist that associates files with the app, but double clicking a file opens the app with no data inside.
Calling
someapp.app/Contents/MacOs/someapp somefile.abc
from the terminal opens the file correctly inside the app.
MyApp::MyApp(int& argc, char**argv): QApplication(argc, argv)
{
...
m_MainWindow = new MainWindows();
m_MainWindow->show();
if(argc > 1 && argv[1])
m_MainWindow->openFile(QString(argv[1]);
else
m_MainWindow->showStartupDialog(); // to create a new document
}
Searching around I found that I should somehow implement QFileOpenEvent... how ?
This example looks good... but I don't understand how to combine the constructor and the event...
How do I make this work ?
(OS X 10.6-10.9, app created using Qt 4.8)
The following is the adapted code, that will respond to the OpenFileEvent either on start or during the normal functioning - and also allow opening o file from command line or creating a new file
MyApp::MyApp(int& argc, char**argv): QApplication(argc, argv)
{
...
m_MainWindow = new MainWindows();
m_MainWindow->show();
if(argc > 1 && argv[1])
m_MainWindow->openFile(QString(argv[1]);
else if (m_macFileOpenOnStart != "")
m_MainWindow->openFile(m_macFileOpenOnStart); // open file on start if it exists
else
m_MainWindow->showStartupDialog(); // to create a new document
}
// responds to FileOpenEvent specific for mac
bool MyApp::event(QEvent *event)
{
switch(event->type())
{
case QEvent::FileOpen:
{
QFileOpenEvent * fileOpenEvent = static_cast<QFileOpenEvent *>(event);
if(fileOpenEvent)
{
m_macFileOpenOnStart = fileOpenEvent->file();
if(!m_macFileOpenOnStart.isEmpty())
{
if (m_MainWindow)
{
m_MainWindow->openFile(m_macFileOpenOnStart); // open file in existing window
}
return true;
}
}
}
default:
return QApplication::event(event);
}
return QApplication::event(event);
}
i'm using a QApplication derived class that emits a signal when file is ready:
#ifndef OPENWITHAPPLICATION_H
#define OPENWITHAPPLICATION_H
#include <QApplication>
#include <QFileOpenEvent>
#include <QMessageBox>
class OpenWithApplication : public QApplication
{
Q_OBJECT
public:
QString fileName;
OpenWithApplication(int &argc, char **argv)
: QApplication(argc, argv)
{
}
signals:
void fileReady(QString fn);
protected:
bool event(QEvent *event)
{
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
fileName = openEvent->file();
emit fileReady(fileName); // the file is ready
}
return QApplication::event(event);
}
};
#endif // OPENWITHAPPLICATION_H
main.cpp connects created OpenWindowApplication with the MainWindow object so once the file is ready, the signal is emitted and received by it for processing
#include "mainwindow.h"
#include <openwithapplication.h>
int main(int argc, char *argv[])
{
OpenWithApplication a(argc, argv);
MainWindow w;
w.connectOpenWithApp(&a);
w.show();
return a.exec();
}
and MainWindow connects fileReady signal with a lambda func that opens the file and updates widget
void MainWindow::connectOpenWithApp(OpenWithApplication*app) {
connect(app, &OpenWithApplication::fileReady, [this](QString fileName){
bw->open(fileName);
bw->update();
});
}
here's the result:

Why does ChangeWindowMessageFilter cause Qt to crash?

Why does the following program crash?
#include <QApplication>
#include <windows.h>
#include <QFrame>
uint MSGFLT_ADD = 1;
uint WM_COPYGLOBALDATA = 0x0049;
int main(int argc, char *argv[])
{
BOOL (*ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
HINSTANCE hDLL = LoadLibraryA("User32.dll"); // Handle to DLL
if (hDLL != NULL){
ChangeWindowMessageFilter = (BOOL (*)(UINT,DWORD))GetProcAddress(hDLL, "ChangeWindowMessageFilter");
}
if (ChangeWindowMessageFilter != NULL){
if (!(*ChangeWindowMessageFilter)(WM_DROPFILES, MSGFLT_ADD)){
printf("Failed to add exception for WM_DROPFILES\n");
}
if (!(*ChangeWindowMessageFilter)(WM_COPYDATA, MSGFLT_ADD)){
printf("Failed to add exception for WM_COPYDATA");
}
if (!(*ChangeWindowMessageFilter)(WM_COPYGLOBALDATA, MSGFLT_ADD)){
printf("Failed to add exception for WM_COPYGLOBALDATA");
}
printf("Added filters\n");
fflush(0);
}
if (hDLL != NULL){
FreeLibrary(hDLL);
}
QApplication a(argc, argv);
QFrame w; //debug crashes here
w.show();
return a.exec();
}
QFrame::QFrame(QWidget* parent, Qt::WindowFlags f)
: QWidget(*new QFramePrivate, parent, f) //on this line in particular
{
Q_D(QFrame);
d->init();
}
EDIT:
if (!(*ChangeWindowMessageFilter)(WM_COPYDATA, MSGFLT_ADD)){ //if i disable this everything works
printf("Failed to add exception for WM_COPYDATA");
}
BOOL (*ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
Your function pointer declaration is wrong. Winapi functions are always __stdcall. Your compiler no doubt uses the default, __cdecl. The stack imbalance you get when you make the call through the function pointer can have many side effects. If you use MSVC++ and run the Debug build then you'll always get an immediate diagnostic. Fix:
BOOL (WINAPI * ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
Fwiw, if this is meant to enable drag+drop into an elevated program then just remove all this, it won't work. D+D is COM based, it doesn't use messages.

how to restart my own qt application?

i just asking myself how to restart my own qt application?
Can somebody please show me an example?
To restart application, try:
#include <QApplication>
#include <QProcess>
...
// restart:
qApp->quit();
QProcess::startDetached(qApp->arguments()[0], qApp->arguments());
I'm taking the other answers solutions, but better. No need for pointers, but there is a need for a ; after the while statement of a do { ... } while( ... ); construct.
int main(int argc, char *argv[])
{
const int RESTART_CODE = 1000;
do
{
QApplication app(argc, argv);
MainWindow main_window(app);
} while( app.exec() == RESTART_CODE);
return return_from_event_loop_code;
}
Assuming that 1337 is your restart code:
main.cxx
int main(int argc, char * argv[])
{
int result = 0;
do
{
QCoreApplication coreapp(argc, argv);
MyClass myObj;
result = coreapp.exec();
} while( result == 1337 );
return result;
}
myClass.cxx
qApp->exit(1337);
To restart a running Qt application (at least in Qt 5.15.2) you can do the following:
#include <QApplication>
#include <QProcess>
//...
QString program = qApp->arguments()[0];
QStringList arguments = qApp->arguments().mid(1); // remove the 1st argument - the program name
qApp->quit();
QProcess::startDetached(program, arguments);
Doing a real process restart without subclassing:
QCoreApplication a(argc, argv);
int returncode = a.exec();
if (returncode == -1)
{
QProcess* proc = new QProcess();
proc->start(QCoreApplication::applicationFilePath());
}
return returncode;
Edit for Mac OS like earlier example.
To restart call
QCoreApplication::exit(-1);
somewhere in your code.
Take a look at How to restart an application thread on qtcentre.org, where muisei gives this code
#define RESTART_CODE 1000
int main(int argc, char *argv[])
{
int return_from_event_loop_code;
QPointer<QApplication> app;
QPointer<MainWindow> main_window;
do
{
if(app) delete app;
if(main_window) delete main_window;
app = new QApplication(argc, argv);
main_window = new MainWindow(app);
return_from_event_loop_code = app->exec();
}
while(return_from_event_loop_code==RESTART_CODE)
return return_from_event_loop_code;
}
I just used the method described above and I noticed that my application crashes on restart.
...then I switched the following lines of code:
if(app) delete app;
if(main_window) delete main_window;
to:
if(main_window) delete main_window;
if(app) delete app;
and it behaves OK. For some reason the window must be deleted first.
Just a note for future readers.
EDIT: ...and a different approach for those who want a real process-restart: You can declare a myApp::Restart() method in your subclass of QApplication. The following version works OK on both MS-Windows & MacOS:
// Restart Application
void myApp::Restart(bool Abort)
{
// Spawn a new instance of myApplication:
QProcess proc;
#ifdef Q_OS_WIN
proc.start(this->applicationFilePath());
#endif
#ifdef Q_OS_MAC
// In Mac OS the full path of aplication binary is:
// <base-path>/myApp.app/Contents/MacOS/myApp
QStringList args;
args << (this->applicationDirPath() + "/../../../myApp.app");
proc.start("open", args);
#endif
// Terminate current instance:
if (Abort) // Abort Application process (exit immediattely)
::exit(0);
else
this->exit(0); // Exit gracefully by terminating the myApp instance
}
This slight variation on Rubenvb's idea works with PyQt. clearSettings is the method that triggers the restart.
class GuiMain
#Most of implementation missing
def clearSettings(self):
#Clearing the settings missing
QApplication.exit(GuiMain.restart_code)
restart_code = 1000
#staticmethod
def application_main():
"""
The application's main function.
Create application and main window and run them.
"""
while True:
app = QApplication(sys.argv)
window = GuiMain()
window.show()
ret = app.exec_()
if ret != GuiMain.restart_code:
break
del window
del app
Here is the code:
main.cpp:
int main(int argc, char *argv[])
{
int currentExitCode = 0;
do {
QApplication a(argc, argv);
MainWindow w;
w.show();
currentExitCode = a.exec();
} while( currentExitCode == MainWindow::EXIT_CODE_REBOOT );
return currentExitCode;
}
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
static int const EXIT_CODE_REBOOT;//THIS IS THE IMPORTANT THING TO ADD TO YOUR CODE
~MainWindow();
private slots:
void slotReboot();//AND THIS ALSO
//ALL THE OTHER VARIABLES
}
The slotReboot() is the slot that will receive the signal of the QAction I'm going to show in the mainwindow.cpp
mainwindow.cpp
First initialize EXIT_CODE_REBOOT :
int const MainWindow::EXIT_CODE_REBOOT = -123456789;
and declare a QAction pointer:
QAction* actionReboot;
then in the MainWindow constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
actionReboot = new QAction( this );
actionReboot->setText( tr("Restart") );
actionReboot->setStatusTip( tr("Restarts the application") );
connect( actionReboot, SIGNAL (triggered()),this, SLOT (slotReboot()));
}
And finally you need to send the signal (in the part of your code you need), in this way:
actionReboot->trigger();
I did the code I showed following these instructions: How to make an application restartable - Qt Wiki
You can use my open source library:
https://marketplace.qt.io/products/main-loop-wdt-for-qt-qml
It's a watchdog timer for the main qt loop, but I have a function for forced reboot, with different strategies: startdetached + exit, exec system call on Linux / macOS, and delayed restart (for example, exit and restart after 3 seconds)