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

C++ Discussion :

Problème pour rendre la main avec la fonction System() sous Windows


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 13
    Points : 5
    Points
    5
    Par défaut Problème pour rendre la main avec la fonction System() sous Windows
    Bonjour à tous,

    J'ai crée un programme en C++ pour savoir qui utilise un logiciel en particulier sur le réseau en écrivant la liste des utilisateurs en cours dans un fichier texte sur une ressource partagée. Au lieu de lancer le programme via le raccourci habituel, j'ai un fichier .ini qui contient le nom d'utilisateur et la commande à lancer (qui est lancée avec System()). Je précise que la commande doit être libre (dans le fichier ini) et ne pas être en dur dans le code C++, notamment s'il y a des arguments, à ne pas coder dans le code C++, tout doit se passer au niveua du fichier .ini.

    Sous Linux, mon programme fonctionne parfaitement, il inscrit l'utilisateur dans le fichier journal, lance le programme, et quand on quitte le programme, il enlève l'utilisateur du fichier journal.

    Seulement, le but est de le faire fonctionner sous Windows (je l'ai compilé sous Visual Studio) et quand je lance la commande avec System("C:\Windows\System32\calc.exe") par exemple, il rend la main, comme si on lançait la commande avec le "&" final sous Linux, ce qui est le comportement par défaut sous Windows. Y a-t-il moyen que System() attende la fin du processus lancé au lieu de rendre tout de suite la main ?

    Merci.

    Jérôme.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 074
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    Franchement, je trouve votre "solution" très bricolé.
    Pour une solution sous Windows au niveau du domaine entier, WMI est ton ami:
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

    Si vous utilisez cette cochonnerie de "system" de Win32, lisez la documentation ATTENTIVEMENT (vous verrez bien que c'est de la m....).
    https://msdn.microsoft.com/en-us/library/b4b6wz4t.aspx

    Vous êtes, en plus de mettre toute la sécurité du système en PLS, dépendant de l'interpréteur de commande de l'OS, qui est celui qui traine, GG.

    Quitte à faire du portable, POSIX est ton ami :
    https://msdn.microsoft.com/en-us/library/431x4c1w.aspx

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Sous Windows, tous les programmes qui ne sont pas des programmes Console rendent la main immédiatement. Pour lancer un processus et toujours en attendre la fin, il faut utiliser CreateProcess() et WaitForSingleObject(). Mais attention, ce n'est pas toujours fiable s'il y a déjà une instance du même programme qui tourne: Certains programmes contactent l'instance existante, lui disent d'ouvrir une nouvelle fenêtre, puis se terminent.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 13
    Points : 5
    Points
    5
    Par défaut
    Merci pour vos différentes réponses. J'assume le côté bricolé et peu sûr.

    Pour parler franchement, je ne sais pas comment mettre en œuvre CreateProcess() et WaitForSingleObject(), mais d'après mes essais il ne me semble pas que ça accepte des char * avec les arguments dedans, de même que la famille des fonctions exec() avec la dernière lettre qui change. En revanche, les bugs avec de multiples instances ne sont pas gênants.

    J'ai réussi à reproduire le comportement que je veux avec "start /wait c:\windows\system32\calc", mais une fois encapsulé dans une commande system(), ça rend quand même la main alors que lancé depuis une console, ça garde bien la main.

    Je veux bien une aide avec un bout de code si j'ai mal compris les explications.

    Merci.

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Quand on ne sait pas, on se renseigne ca évite les bêtises.
    Regarde donc la documentation
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 13
    Points : 5
    Points
    5
    Par défaut
    Ternel, J'ai suivi tes conseils, je me suis renseigné et j'ai regardé la doc suivante :

    https://msdn.microsoft.com/fr-fr/lib...(v=vs.85).aspx

    Donc j'ai mis dans mon programme le code suivant, largement copié-collé sans trop comprendre (j'ai dû caster mon char * en TCHAR * au passage, encore un type que je ne connaissais pas) :

    Code : 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
     
    STARTUPINFO si;
    	PROCESS_INFORMATION pi;
     
    	ZeroMemory(&si, sizeof(si));
    	si.cb = sizeof(si);
    	ZeroMemory(&pi, sizeof(pi));
     
    	CreateProcess(NULL,
    		(TCHAR *)("c:/windows/system32/calc.exe"),
    		NULL,           // Process handle not inheritable
    		NULL,           // Thread handle not inheritable
    		FALSE,          // Set handle inheritance to FALSE
    		0,              // No creation flags
    		NULL,           // Use parent's environment block
    		NULL,           // Use parent's starting directory 
    		&si,            // Pointer to STARTUPINFO structure
    		&pi);           // Pointer to PROCESS_INFORMATION structure
    Et à l'exécution, j'obtiens un magnifique :

    Exception non gérée*: System.AccessViolationException: Tentative de lecture ou d'écriture de mémoire protégée. Cela indique souvent qu'une autre mémoire est endommagée.
    à CreateProcessW(Char* , Char* , _SECURITY_ATTRIBUTES* , _SECURITY_ATTRIBUTES* , Int32 , UInt32 , Void* , Char* , _STARTUPINFOW* , _PROCESS_INFORMATION* )
    à main(Int32 argc, SByte** argv) dans c:\users\jerome\documents\visual studio 2015\projects\quiutilise\quiutilise\quiutilise.cpp:ligne 155
    à _mainCRTStartup()

    Une idée ?

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 074
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    System.AccessViolationException
    Otez-moi d'un doute, vous ne faites pas du C++/CLI par hasard ?
    Si c'est le cas, alors pourquoi se faire chier avec ces API Win32 en C quand le Framework .NET donne la même chose mais en bien plus simple ?

    J'ai l'impression que vous ne comprenez pas que le prompt de CMD.EXE (la console), la primitive "system" et CreateProcess ne sont vraiment pas la même chose.

    Dans "la console", c'est juste que vous dialoguez avec le programme "CMD.EXE" via une console qui la lui-même créé.
    Donc, quand vous tapez "start /wait c:\windows\system32\calc" dans une console, c'est "CMD.EXE" qui va lire et interpréter la commande.
    le "/wait" est lu par "CMD.EXE" et c'est lui qui attend la fin du processus qu'il a créé via "CreateProcess", avec un appel à "WaitForSingleObject" en utilisant l'handle retourné par "CreateProcess".
    Vous devrez faire la même chose dans votre programme "à la bricole".
    le "start", c'est pour que "CMD.EXE" lance un autre "CMD.EXE" (Inception Inside ) qui exécutera le contenu du script passé en paramètre.
    Donc, on n'a un "CMD.EXE" qui affiche une console, qui lance un autre "CMD.EXE" qui à sa propre console et qui exécute directement le contenu d'un fichier.
    le 1er "CMD.EXE" attend la fin du second "CMD.EXE" avec un "WaitForSingleObject".

    Avec "system", c'est la fête à la saucisse, vous donnez une "commande" et le système prend un programme choisi presque au pif ("CMD.EXE" peut-être, mais c'est pas sûr, ça peut même être votre navigateur par défaut (joie!) ) et le lance en donnant comme argument de ligne de commande (les paramètres passés à la fonction Main) ce que vous avez donné comme paramètre à "system", mais agrémenté de tout un tas de trucs de configuration qui trainent en base de registre.

    Avec "CreateProcess", vous êtes dans le dur, c'est à vous de faire le vrai boulot. (enfin, ça casse pas 3 pattes à un canard non plus).

    j'ai dû caster mon char * en TCHAR * au passage
    OK, TCHAR n'est pas égale à char quand vous compilez avec l'option UNICODE, c'est bien, mais cela explique aussi pourquoi vous vous prenez une exception dans la tronche.

    en TCHAR * au passage, encore un type que je ne connaissais pas
    RTFM :
    https://msdn.microsoft.com/fr-fr/lib...(v=vs.85).aspx

    Si vous avez bien lu et compris la documentation, vous savez maintenant que ce cast est une énorme connerie et que la MACRO L (ou d'autres comme TEXT etc...) est votre amie.

    Normalement, avec l'exemple que vous avez donné, sans le cast et la MACRO qui va bien, vous devriez vous en sortir dans votre bricolage.

    Franchement, quand on voit tous les outils qu'offre M$, ce bricolage m'exaspère.

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 13
    Points : 5
    Points
    5
    Par défaut
    Bon, j'ai regardé les macros L et TEXT, j'ai mis L"c:/windows/system32/calc.exe" ou TEXT("c:/windows/system32/calc.exe") à la place, mais pareil, il me met toujours la tentative de lecture ou d'écriture de mémoire protégée.

    Merci quand même pour l'info, ce n'est pas du C++/CLI, et j'aimerais que le programme fonctionne sur un peu toutes les plates-formes Windows (7 et +), même qui n'ont pas de runtimes de framework.net.

    Donc en résumé, je n'arrive pas à lancer la calculatrice dans un thread séparé et que le programme principal rende la main quand je ferme la calculatrice. Peut-être que pour un spécialiste, ça ne casse pas 3 pattes à un canard, mais pour moi qui, en matière de thread, n'ai appris que les primitives système Unix il y a 20 ans, tout cela est fort nouveau.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Bon, j'ai regardé les macros L et TEXT, j'ai mis L"c:/windows/system32/calc.exe" ou TEXT("c:/windows/system32/calc.exe") à la place, mais pareil, il me met toujours la tentative de lecture ou d'écriture de mémoire protégée.
    Le second paramètre de CreateProcess() demande une chaîne modifiable. Tu peux donc essayer ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    	STARTUPINFO si = {0};
    	PROCESS_INFORMATION pi = {0};
    	TCHAR commandLine[] = TEXT("c:/windows/system32/calc.exe");
    	si.cb = sizeof(si);
     
    	CreateProcess(NULL,
    		commandLine,
    		NULL,           // Process handle not inheritable
    		NULL,           // Thread handle not inheritable
    		FALSE,          // Set handle inheritance to FALSE
    		0,              // No creation flags
    		NULL,           // Use parent's environment block
    		NULL,           // Use parent's starting directory 
    		&si,            // Pointer to STARTUPINFO structure
    		&pi);           // Pointer to PROCESS_INFORMATION structure
    Citation Envoyé par cogidis Voir le message
    Merci quand même pour l'info, ce n'est pas du C++/CLI, et j'aimerais que le programme fonctionne sur un peu toutes les plates-formes Windows (7 et +), même qui n'ont pas de runtimes de framework.net.
    Que tu le veuilles ou non, System.AccessViolationException, c'est du .Net. Tu as dû créer un projet du mauvais type (ou avec le mauvais Visual Studio, dans le cas des versions Express)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 074
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    j'aimerais que le programme fonctionne sur un peu toutes les plates-formes Windows (7 et +), même qui n'ont pas de runtimes de framework.net.
    A quel OS Windows pensez-vous ?
    Car le Framework .NET est pré-installé depuis WinXP SP2.

    dans un thread séparé
    Ok, vous confondez thread et processus, cela n'a pas grand-chose à voir.

    il me met toujours la tentative de lecture ou d'écriture de mémoire protégée.
    C'est peut-être le moment d'utiliser ENFIN le débogueur ?

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 13
    Points : 5
    Points
    5
    Par défaut
    Oui, OK, thread et processus, ça n'est pas très heureux. Le déboggueur, je ne sais pas l'utiliser (comme ça, c'est dit), je viens du monde Linux + vi, je développe de manière tout à fait accessoire par rapport au système ou réseau.

    Bref, je me suis dépanné avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    system(programme.enchaine());
     
    	Sleep(2000);
     
    	while (ProcessRunning((wchar_t *) nomprocessus.enchaine() ))
    	{
    		Sleep(1000);
     
    	}
    Je sais que je m'enfonce un peu plus dans le bricolage, mais au moins ça fonctionne. "programme" contient le chemin du programme à exécuter et "nomprocessus" contient le nom tel qu'on le voit dans le gestionnaire de tâches.

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

Discussions similaires

  1. fonction system() sous windows avec des blancs, des arguments, etc.
    Par eric1708 dans le forum Bibliothèques, systèmes et outils
    Réponses: 10
    Dernier message: 12/08/2014, 08h43
  2. Réponses: 2
    Dernier message: 13/08/2012, 14h12
  3. Réponses: 1
    Dernier message: 18/02/2012, 15h20
  4. Réponses: 9
    Dernier message: 29/04/2008, 13h38
  5. Réponses: 1
    Dernier message: 17/05/2004, 11h29

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