IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion :

[QHttp] Télécharger un exécutable et le lancer

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut [QHttp] Télécharger un exécutable et le lancer
    Bonjour à tous.
    Je m'arrache les cheveux depuis quelques jours. Ce que je veux faire est simple : télécharger un exécutable, puis l'exécuter.

    Le téléchargement fonctionne à merveille, le fichier obtenu n'est pas corrompu, il est similaire en tout point à l'original (j'arrive à l'exécuter et-tout-ça).
    En revanche, le lancement pause problème, la fonction QProcess::start() retourne l'erreur 5 (Erreur inconnue). Il semblerait en effet que lorsque cette fonction est appelée par mon programme, le fichier téléchargé ne fait que 25994 octets au lieu des 34816 (que font programme.exe sur le serveur et programme.exe sur mon disque une fois tout terminé).

    Voici comment j'ai procédé :
    Dans le main je crée un QHttp et je lui demande de télécharger mon programme.exe ; je connecte aussi le signal done(bool) à un slot perso.
    Ce slot ouvre un fichier log, vérifie que programme.exe est bien présent, et tente de l'exécuter.

    Voici le log créé :
    Upgrading date : jeu. 30. oct. 14:07:08 2008
    Successfull download of the new version of programme.exe
    Launching programme.exe (25994 Bytes) : Error #5
    Voici mon code :
    Code C++/Qt4 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    #include <QtCore>
    #include <QtNetwork>
    #include <QProcess>
     
    const QString qs_nrchost = "programme.exe";
    const QString qs_log = "upgrading.log";
     
    class upgrader : public QObject
    {
    Q_OBJECT
    public slots:
    	// Slot appelé lorsque le téléchargement est fini
    	void onDownloadComplete(bool error)
    	{
    		// Log
    		QFile qf_log(qs_log);
    		QTextStream qts_out;
    		bool bol_logOpened = qf_log.open(QIODevice::Append|QIODevice::Text);
    		if(bol_logOpened)
    		{
    			qts_out.setDevice(&qf_log);
    			qts_out << "\nUpgrading date : " << QDateTime::currentDateTime().toString() << "\n";
    		}
    		if(error)
    		{
    			// Si le téléchargement s'est mal déroulé
    			if(bol_logOpened)
    			{
    				qts_out << "Error while downloading the new version of " << qs_nrchost << "\n";
    				qts_out << "Deleting compromised file :" << (QFile::remove(qs_nrchost)?"OK":"Error") << "\n";
    			}
    			return QCoreApplication::quit();
    		}
    		else
    		{
    			// Si le téléchargement s'est bien déroulé
    			bool bol_nrchostOpened = false;
    			QFile *qf_nrchost = new QFile(qs_nrchost);
    			bol_nrchostOpened = qf_nrchost->open(QIODevice::ReadOnly);
    			if(bol_logOpened)
    			{
    				qts_out << "Successfull download of the new version of " << qs_nrchost << "\n";
    				if(bol_nrchostOpened)
    				{
    					qts_out << "Launching nrchost.exe (" << qf_nrchost->size() << " Bytes) : ";
    					delete(qf_nrchost);
    				}
    				else
    				{
    					qts_out << "Error #" << qf_nrchost->error() << " : Unable to open " << qs_nrchost << "\n";
    					qts_out << "Launching " << qs_nrchost << " : ";
    					delete(qf_nrchost);
    				}
     
    				// Launch nrchost.exe
    				QProcess qp_nrchost;
    				if(qp_nrchost.startDetached(qs_nrchost))
    					qts_out << "OK\n";
    				else
    					qts_out << "Error #" << qp_nrchost.error() << "\n";
    			}
    			return QCoreApplication::quit();
    		}
    	}
    };
     
    int main(int argc, char* argv[])
    {
    	QCoreApplication app(argc, argv);
     
    	// Instance de l'interface d'upgrade
    	upgrader slut;
     
    	// Téléchargement de la mise à jour
    	QFile qf_nrchost(qs_nrchost);
    	QHttp qh_http("www.example.com");
    	qh_http.get("/dir/"+qs_nrchost, &qf_nrchost);
     
    	// Gestion du fichier téléchargé
    	app.connect(&qh_http, SIGNAL(done(bool)), &slut, SLOT(onDownloadComplete(bool)));
     
    	// Exécution
    	return app.exec();
    }
     
    #include "main.moc"


    Merci beaucoup pour votre aide.

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    A mon avis, c'est que le QFile qui écrit l'exe n'as pas finie de l'écrire sur le disque. Y as une partie encore en mémoire.
    Il faudrait que tu le ferme avant de le lancer.
    Ou mieux, ne donne pas de QFile au QHttp et quand le téléchargement est finie, récupère directement le flux pour l'écrire dans un fichier.
    Attention, ton fichier doit être ouvert en mode binaire

  3. #3
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut
    Merci pour ton aide.

    J'ai modifié mon code comme tu l'a conseillé. Je récupère donc un pointeur vers mon QHttp depuis le slot activé par done(bool). Je regarde combien d'octets sont près à être lus (34816 \o/), je récupère ces données dans un QByteArray (miracle, son .count() retourne 34816 \o/) et finalement j'écris ça dans un fichier (ouvert en binaire) grâce à un QDataStream ... et là, c'est le drame : 34820 octets écrits :'(

    Code C++/Qt4 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    QHttp *qh_http = qobject_cast<QHttp *>(sender());
    QDataStream qds_write(qf_nrchost);
    qts_out << qh_http->bytesAvailable() << "\n";
    QByteArray qba_data = qh_http->readAll();
    qts_out << qba_data.count();
    qds_write << qba_data;

    Un dernier petit coup de pouce plz ?
    J'ai comparé les deux fichiers, ils sont strictement identiques si l'on omet les 4 octets supplémentaires en début de fichier : 0000 8800 (HEX) = 34816 (DEC) \o/. Je suppose que cela doit être du au fait que les QByteArray stockent leur taille dans les 32 premiers bits ... mais si j'utilise la ligne suivante, cela revient au même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    qds_write << *(qba_data.constData());

  4. #4
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    et en écrivant comme cela?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    QHttp *qh_http = qobject_cast<QHttp *>(sender());
    if (qh_http)
    {
    QFile qf_nrchost(qs_nrchost);
    qf_nrchost.open(QIODevice::WriteOnly);
    qf_nrchost.write(qh_http->readAll());
    }
    Evite les pointeur inutilise, comme le QFile dans ton code

  5. #5
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut
    Ça fonctionne à merveille. Merci beaucoup.

  6. #6
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut Résolution du problème
    Et voici mon code final, espérant qu'il pourra aider ceux qui rencontrerait le même problème que moi. Merci à Mongaulois.

    Ce code n'est pas fait pour être réutilisé tel quel, il est juste fourni à titre d'exemple. Il est aussi perfectible. Merci à celui qui travaillerait sur le même sujet de poster un code plus aboutit.

    Code C++/Qt4 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    #include <QtCore>
    #include <QtNetwork>
    #include <QProcess>
    #include <QTimer>
     
    const QString qs_nrchost = "programme_mis_a_jour.exe";
    const QString qs_log = "journal_de_l_operation.log";
     
    class upgrader : public QObject
    {
    Q_OBJECT
    public slots:
    	// Slot appelé lorsque le téléchargement est fini
    	void onDownloadComplete(bool bol_errorWhiledownload)
    	{
    		//
    		// Drapeaux pour le log
    		bool bol_qhttp = false;
    		bool bol_nrchostOpened = false;
    		bool bol_nrchostWellWritten = false;
    		bool bol_nrchostWellStarted = false;
    		//
    		// Variables globales
    		QHttp *qh_http = NULL;
    		QFile qf_nrchost;
    		qint64 q64_bytesWrittens = 0;
    		qint64 q64_bytesAvailable = 0;
    		QProcess qp_nrchost;
    		int int_statusCode = 0;
     
    		// Récupération de la requete HTTP
    		if(qh_http = qobject_cast<QHttp *>(sender()))
    		{
    			bol_qhttp = true;
    			int_statusCode = qh_http->lastResponse().statusCode();
    		}
    		// Si le téléchargement s'est bien déroulé (200=OK, cf. spec HTTP/1.1)
    		if(!bol_errorWhiledownload && int_statusCode == 200)
    		{
    			// Création du ficher exécutable (vide)
    			qf_nrchost.setFileName(qs_nrchost);
    			bol_nrchostOpened = qf_nrchost.open(QIODevice::WriteOnly);
     
    			// Ecriture de l'exécutable
    			q64_bytesAvailable = qh_http->bytesAvailable();
    			q64_bytesWrittens = qf_nrchost.write(qh_http->readAll());
    			bol_nrchostWellWritten = q64_bytesAvailable == q64_bytesWrittens;
    			qf_nrchost.close();
    		}
    		else
    			QFile::rename(qs_nrchost + ".bak", qs_nrchost);
     
    		//
    		// Lancement du programme
    		bol_nrchostWellStarted = qp_nrchost.startDetached(qs_nrchost);
     
    		//
    		// Création du fichier de log
    		QFile qf_log(qs_log);
    		QTextStream qts_out;
    		if(qf_log.open(QIODevice::Append|QIODevice::Text))
    		{
    			const QString qs_ok = "[OK]";
    			const QString qs_error = "[FAIL]";
    			qts_out.setDevice(&qf_log);
     
    			qts_out << "----------------------------------------------------------\n";
    			qts_out << "Upgrading " << qs_nrchost << "...\n";
    			qts_out << "Date : " << QDateTime::currentDateTime().toString() << "\n\n";
    			qts_out << "Sending HTTP request ................ " << (bol_qhttp ? qs_ok : qs_error) << "\n";
    			qts_out << "Downloading " + QString::number(q64_bytesAvailable, 10).rightJustified(6, ' ') \
    						+ " Bytes ............ ";
    			if(bol_errorWhiledownload)
    				qts_out << qs_error + (bol_qhttp ? " Error #"+QString::number(qh_http->error(), 10) : "");
    			if(bol_qhttp && int_statusCode != 200)
    				qts_out << qs_error + " HTTP Error " + QString::number(int_statusCode, 10);
    			if(!bol_errorWhiledownload && int_statusCode == 200)
    				qts_out << qs_ok + " HTTP " + QString::number(int_statusCode, 10);
    			qts_out << "\n";
    			qts_out << "Creation of the file ................ " << (bol_nrchostOpened ? qs_ok : \
    						qs_error + " Error #" + QString::number(qf_nrchost.error(), 10))\
    						<< "\n";
    			qts_out << "Writting of the file ................ " << \
    						( \
    							bol_nrchostWellWritten ? qs_ok : qs_error + " Bytes balance = " \
    							+ QString::number(q64_bytesAvailable - q64_bytesWrittens, 10) \
    						) << "\n";
    			qts_out << "Starting of the program ............. " << \
    						(bol_nrchostWellStarted ? qs_ok : \
    						qs_error + " Error #"+ QString::number(qp_nrchost.error(), 10)) << "\n";
    			qts_out << "\n\n";
    		}
    		return QCoreApplication::quit();
    	}
    };
     
    int main(int argc, char* argv[])
    {
    	QCoreApplication app(argc, argv);
    		// Instance de l'interface d'upgrade
    	upgrader slut;
    	// Sauvegarde de l'ancienne version
    	QFile::remove(qs_nrchost + ".bak");
    	if (!QFile::rename(qs_nrchost, qs_nrchost + ".bak"))
    	{
    		slut.onDownloadComplete(false);
    		return 1;
    	}
    	// Création de la connexion au serveur
    	QHttp qh_http("www.example.com");
    	// Demande au serveur
    	QTimer timer;
    	app.connect(&timer, SIGNAL(timeout()), &qh_http, SLOT(abort()));
    	timer.start(30000); // durée max pour la requête, après quoi celle-ci est abandonnée
    	qh_http.get("/nrchost/"+qs_nrchost);
    	// Gestion du fichier téléchargé
    	app.connect(&qh_http, SIGNAL(done(bool)), &slut, SLOT(onDownloadComplete(bool)));
    	// Exécution
    	return app.exec();
    }
     
    #include "main.moc"

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [EJB3] Télécharger et exécuter du code distant localement
    Par igor21 dans le forum Java EE
    Réponses: 0
    Dernier message: 27/05/2010, 20h14
  2. télécharger et exécuter
    Par inster dans le forum Windows Forms
    Réponses: 3
    Dernier message: 29/01/2010, 02h05
  3. [Unix] Lancer un exécutable
    Par Flo2 dans le forum Cobol
    Réponses: 2
    Dernier message: 02/10/2005, 21h57
  4. Lancer un exécutable en PL/SQL
    Par Doctor Z dans le forum PL/SQL
    Réponses: 23
    Dernier message: 01/02/2005, 14h51
  5. Lancer exécutable en asynchrone
    Par ZeKiD dans le forum ANT
    Réponses: 4
    Dernier message: 30/03/2004, 16h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo