Projet

Général

Profil

Lancement exécutable sur Windows avec gestion de demande des privilèges

Préambule

Cette page résulte d'une volonté de contrôle du redémarrage d'une application Qt (sous Windows/Linux et Mac).
Sous Linux, le simple fait de lancer un QProcess détaché avant de stopper l'application en cours est suffisant.
Sous Windows, cela fonctionne en développement, mais pas en production (les exécutables sont contenus dans C:\Programs Files\...)
Le système d'exploitation Mac n'a pas été encore testé.

La solution sous Linux

void MyClass::restartApp
{
    /* On lance un processus détaché avec l'exécutable de l'application */
    if(!QProcess::startDetached(QApplication::applicationFilePath())){
        qDebug() << "Redemarrage automatique non disponible";
        QMessageBox::warning(0, "Attention", trUtf8("Le redémarrage automatique a échoué.\n Veuillez relancer l'application manuellement"));
    }
    else{
        qDebug() << "Redemarrage automatique en cours.";
    }

    abeApp->exit(-9); /* un code différent synonyme de redémarrage (une énumération  serait la bienvenue ici :p) */
}

La solution sous Windows

Il faut utiliser les librairies shellapi et windows, afin d'avoir accès au shell Windows.
Les différentes fonctions offertes par ces librairies vont nous permettre de récupérer les codes de retour des processus lancés, et même de pourvoir effectuer une demande d'élévation de privilège (la petite boite jaune sous Windows qui demande les droits administrateur). La documentation officielle est à cette adresse : http://msdn.microsoft.com/en-us/library/windows/desktop/bb762154%28v=vs.85%29.aspx.

Voici la même méthode que décrite au-dessus, avec la prise en compte du système Windows :p.

void MyClass::restartApp
{
    qDebug() << "Redemarrage de l'application en cours";
    const QString executable = QApplication::applicationFilePath();

/* Si on est sur Windows, on inclut les fichiers qu'il faut */
#ifdef Q_OS_WIN
#include <windows.h>
#include <shellapi.h>

    qDebug() << "Lancement Shell Execute";

    /* On récupère le résultat de notre tentative de redémarrage (pour l'explication des paramètres --> cf the MSDN doc) */
    int result = (int)::ShellExecuteA(0, "open", executable.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);

    /* Si le résultat est égal à ACCESSDENIED, c'est qu'on a pas les droits adéquats. On retente avec l'option "runas", qui se chargera de la pop-up "Exécuter avec les droits administrateur" */
    if(SE_ERR_ACCESSDENIED == result){
        qDebug() << "Lancement Shell Execute avec demande de privileges admin";
        /* On demande alors l'élévation */
        result = (int)::ShellExecuteA(0, "runas", executable.toUtf8().constData(), 0, 0, SW_SHOWNORMAL);
    }
    if(result <= 32)
    {
        /* Gestion des erreurs (bon c'est sommaire, mais concis :p ) */
        qDebug() << "ERROR SHELLEXECUTE" << result;
    }

#else
    /* On est sur un Linux (il faudrait aussi en #ifdef :p je l'avoue) */

    /* On lance un processus détaché avec l'exécutable de l'application */
    if(!QProcess::startDetached(QApplication::applicationFilePath())){
        qDebug() << "Redemarrage automatique non disponible";
        QMessageBox::warning(0, "Attention", trUtf8("Le redémarrage automatique a échoué.\n Veuillez relancer l'application manuellement"));
    }
    else{
        qDebug() << "Redemarrage automatique en cours.";
    }

#endif
    abeApp->exit(-9); /* un code différent synonyme de redémarrage (une énumération  serait la bienvenue ici :p) */
}

Redmine Appliance - Powered by TurnKey Linux