wxDev.fr, le portail francophone consacré à wxWidgets ! ( The french portal for wxWidgets )  
Esp. membre
Recheche rapide



Recherche avancée
Statistiques
Membres inscrits :2359

Membres en ligne : 0
Invités en ligne : 1
Pub hébergeur
Pourquoi cette pub ?

Valid XHTML 1.0 Transitional

Valid CSS2

Menu Snippets (navigation):
Pages: 1    Accueil » Snippets » Système
» [wxExecute] : Récupérer le résultat de la ligne de commande
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: 1364
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.
Contenu du snippet :
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;
}
 
Explications finales :
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'
Commentaires
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: 1364
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: 40
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):
Pages: 1    Accueil » Snippets » Système
» [wxExecute] : Récupérer le résultat de la ligne de commande