3

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

Anthony Geoghegan
  • 11,533
  • 5
  • 49
  • 56
Haris
  • 13,645
  • 12
  • 90
  • 121
  • 1
    what happen if you try/catch you crash, in catch unlock the shared memory then exit the app? – Thomas Ayoub Feb 18 '15 at 09:42
  • Ok, It might be possible, but in my case my original project contains many source file(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 – Haris Feb 18 '15 at 09:49
  • What does `QSharedMemory::error()` returns after `sharedMem.create` failed? *Off-topic* - you can use static function `QMessageBox::critical(...)` instead of 4 lines you used – borisbn Feb 18 '15 at 10:01
  • Thanks for the suggestion, QSharedMemory::error() returns 4 on both crash and instance exist(previous app running normally) there. – Haris Feb 18 '15 at 10:12
  • I Got it working by using the solution [here][1] [1]: http://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection/28172162#28172162 – Haris Feb 18 '15 at 11:45

2 Answers2

3

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.

Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
  • Hi, suppose the application is running and the user start the application again, then how can I mange with above solution, means setExitedNormaly still false. – Haris Feb 18 '15 at 10:58
  • 1
    @Haris I don't really know... Maybe with a second setting storing the number of opened instance ? – Thomas Ayoub Feb 18 '15 at 12:30
1

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);
aminM
  • 51
  • 7