Membres inscrits :2359
Membres en ligne : 0
Invités en ligne : 8


|
Menu Snippets (navigation): |
Détails du snippet : [wxExecute] : Récupérer le résultat de la ligne de commande |
Informations sur l'auteur de ce snippet : | |

Hors ligne
| Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1383
Snippets: 25
Tutoriels: 6
|
Introduction / Description : | |
Bonjour à tous. La fonction wxExecute permet, comme son nom l'indique, de lancer l'exécution d'un programme externe. Voici deux façons de l'utiliser : - la 1 ère exécute la commande et attend la fin de cette exécution pour rendre la main au programme principal (c'est l'exécution synchrone). - la 2 ème exécute la commande et rend tout de suite la main au programme principal (c'est l'exécution asynchrone). Ces deux méthodes ont chacunes leurs avantages et leurs inconvénients : - l'exécution synchrone est très facile à mettre en oeuvre, mais elle bloque le programme principal, ce qui peut être gênant dans le cas d'une commande nécessitant un temps d'exécution un peut long. - l'exécution asynchrone et un peu plus délicate à mettre en oeuvre, mais elle permet par exemple d'afficher une barre de progression pour faire patienter l'utilisateur. Dans les deux cas, il peut parfois être utile de récupérer le résultat de la ligne de commande, afin d'informer l'utilisateur des résultats obtenus. C'est ce que nous allons voir maintenant.
Première méthode : l'exécution synchrone.Le principe est simple : - On crée un wxArrayString qui va recevoir le résultat de la ligne de commande (le flux de sortie stdout). - On crée éventuellement un autre wxArrayString pour recevoir les erreurs si on veut les traiter (le flux de sortie stderr). - On lance la commande wxExecute() - On traite le contenu du ou des wxArrayString quand l'exécution est terminée.
Code wxWidgets: // Les wxArrayString pour récupérer les flux stdout et stderr wxArrayString arrStdOut,arrStdErr; // On appelle wxExecute avec nos wxArrayString en paramètres wxExecute(_T("commande_à_exécuter"),arrStdOut,arrStdErr,wxEXEC_SYNC); // Pour ne pas récupérer le flux stderr, ça donne : wxExecute(_T("commande_à_exécuter"),arrStdOut,wxEXEC_SYNC); Deuxième méthode : l'exécution asynchrone.Là, le principe est un peu plus compliqué : - Il faut d'abord mettre en place une méthode évènementielle pour recevoir une notification quand l'exécution de la commande sera terminée. - Il faut ensuite créer un objet wxProcess qui va servir à rediriger les flux stdout et stderr. - On lance la commande wxExecute, avec en paramètres un pointeur vers la frame qui désire recevoir la notification de fin de processus, et un pointeur vers le wxProcess créé ci-dessus. - On récupère un wxInputStream permettant de lire le flux stdout au fur et à mesure de l'exécution de la commande. - On récupère éventuellement un autre wxInputstream permettant de lire le flux stderr au fur et à mesure de l'exécution de la commande. - Lorsque l'exécution de la commande est terminée, on reçoit un évènement wxEVT_END_PROCESS.
Code wxWidgets: // Pour simplifier cet exemple, j'utilise une variable booléenne // afin de savoir si l'exécution de la commande est terminée ou non // et je vais juste stocker le résultat du flux stdout dans un wxString class MyFrame : public wxFrame { public: MyFrame(wxWindow *parent, const wxString &title); ~MyFrame(); private: void OnExecuteCommand(wxCommandEvent &event); void OnEndProcess(wxProcessEvent &event); bool m_bIsRunning; DECLARE_EVENT_TABLE(); }; BEGIN_EVENT_TABLE(MyFrame,wxFrame) EVT_END_PROCESS(wxID_ANY, MyFrame::OnEndProcess) END_EVENT_TABLE() // La méthode qui va être appelée lorsque l'exécution sera terminée void MyFrame::OnEndProcess(wxProcessEvent &event) { bIsRunning=false; } void MyFrame::OnExecuteCommand(wxCommandEvent &event) { // On crée l'objet wxProcess wxProcess *process=new wxProcess(this,-1); // On lui indique qu'il doit rediriger les flux de sortie process->Redirect(); wxInputStream *istrm; // Le booléen et le wxString pour ce test bIsRunning=true; wxString sStdOut=_T(""); // On lance l'exécution long lRes=wxExecute(_T("commande_à_exécuter"),wxEXEC_ASYNC,process); // Un buffer pour récupérer les données du wxInputStream char szBuffer[1025]; szBuffer[1024]=0; // La commande est lancée, on peut donc récupérer // le wxInputStream du flux stdout wxInputStream *strmStdOut=process->GetInputStream(); // Ainsi que celui du flux stderr wxInputStream *strmStdErr=process->GetErrorStream(); // Si la commande a bien été lancée, on traite les flux if (lRes!=0) { // Tant que la commande s'exécute while(bIsRunning) { wxGetApp().Yield(); // On traite le flux stdout if (strmStdOut!=NULL) { // S'il y a des données sur ce flux, alors on les lit if (strmStdOut->CanRead()) { strmStdOut->Read(szBuffer,1024); sStdOut.Append((wxString::From8BitData(szBuffer))); } } // Le principe est le même avec le flux stderr } } else { wxMessageBox(_T("Erreur lors du lancement de la commande !")); } // On n'oublie pas de détruire l'objet wxProcess delete process; }
Quelques petites précisions : - Dans les deux cas ci-dessus, l'éventuelle "fenêtre ms-dos ou terminal" reste invisible. Pour la faire apparaitre, il faut ajouter le flag wxEXEC_NOHIDE au dernier paramètre de la commande wxExecute, ce qui donne wxEXEC_SYNC | wxEXEC_NOHIDE dans le premier cas, et wxEXEC_ASYNC | wxEXEC_NOHIDE dans le deuxième cas. - Dans le premier cas, la fenêtre appelante est désactivée pendant tout le temps de l'exécution de la commande. Il est possible de la laisser active en ajoutant le flag wxEXEC_NODISABLE de la même façon que ci-dessus.
Voilà, comme vous pouvez le constater, ça n'était pas très difficile.
@+, et bonne prog !
Xav'
Zoloom (Membre)
Inscrit le : 31-12-2007
Messages: 97
Snippets: 0
Tutoriels: 0
Hors ligne |
Un grand merci pour ce widget, je suis entrain de tester.
Par contre j'ai trouver une petite erreur :
wxInputstream *strmStdErr=process->GetErrorStream(); -> wxInputStream *strmStdErr=process->GetErrorStream()
|
|
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1383
Snippets: 25
Tutoriels: 6
Site web
Hors ligne |
C'est corrigé : merci.
|
Le nouveau portail wxWidgets francophone : www.wxdev.fr Ben en fait, vous y êtes déjà...
|
Alfred83 (Membre)
Lieu: Toulon 83
Inscrit le : 28-12-2007
Messages: 42
Snippets: 0
Tutoriels: 0
Hors ligne |
Merci pour tous ces snippets quelquefois si utiles, mais toujours instructifs. J'utilise depuis longtemps wxexecute en synchrone. Mais la méthode asynchrone que vous nous offrez m'intéresse particulièrement, car elle devrait permettre de mettre en place, à peu de frais, le lancement successif de plusieurs jobs, c'est à dire une possibilité de travailler en batch.
A mon avis le titre de ce snippet est mal choisi: il est beaucoup plus riche en possibilité que son titre ne le laisse supposer. Bien Amicalement.
|
Informaticien bénévole du "Groupement des Intellectuels Aveugles ou Amblyopes" à Toulon, qui publie les trois quarts des livres en braille en France.
|
k3nrdx (Membre)
Inscrit le : 06-03-2009
Messages: 19
Snippets: 0
Tutoriels: 0
Hors ligne |
Bonjour, Dans le cas où je suis dans une Dll, si j'utilise wxExecute une exception est lever car il n'y a pas de wxApp. Qu'est ce que je pourrai utiliser pour exécuter un .exe de façon multi-os?
J'ai forcement un main qui appel ma dll, pkoi wxExecute ne prend pas ce contexte? Merci.
|
|
volfoni54 (Membre)
Lieu: Volfoni
Inscrit le : 14-09-2008
Messages: 15
Snippets: 0
Tutoriels: 0
Hors ligne |
Bonjour à tous,
A quoi sert la ligne wxGetApp().Yield(); ?? Existe t-il un moyen de s'en passer car la compil se passe mal et je n'arrive pas à trouver une parade...
Merci
Volfoni54
|
|
Menu Snippets (navigation): |
|