1 pièce(s) jointe(s)
Questions d'utilisation des API's de Windows
Bonjour à tous,
Je reviens sur le forum pour faire un petit appel aux spécialistes des API's de Windows. Mes questions font suite au petit développement que j'ai commencé à réaliser et que j'ai exposé dans le message
Je ne viens pas pour mon application directement car elle n'a pas suscité un grand intérêt mais, principalement, pour des fonctions générales des API's que je n'arrive pas à trouver ou à utiliser malgré le temps que je passe à lire la documentation "https://msdn.microsoft.com/en-us" et les tutoriels.
J'arrive certes à faire fonctionner mon programme mais d'une manière qui ne me convient pas car non exportable.
J'aurais donc quatre questions qui m’embarrassent:
J'ai un programme, le processus-père, qui lance un processus-fils avec la fonction API "CreatProcess(...)" :
1°) - Comment détecter dans le processus-père que le processus-fils n'existe plus ?
Je n'ai rien trouvé et n'ai pas réussi à tirer partie de la structure "PROCESS_INFORMATION".
Cette situation peut être fréquente. Si le processus-fils termine son exécution, il est indispensable que le processus-père le sache pour prendre des dispositions à savoir au moins celle de sortir à son tour. J'ai regardé du côté des process_id : je n'ai rien trouvé !...
2°) - Comment le processus-père peut-il forcer le processus-fils à terminer son exécution ?
Voire même à le tuer, ce qui ne me paraît pas très régulier. J'ai bien essayé la fonction "TerminateProcess(...)" mais elle ne reconnait pas le handle qui se trouve dans la structure "PROCESS_INFORMATION".
3°) - Comment programmer le dialogue processus-père <=> processus-fils pour que le processus-père sache que le processus-fils réclame une saisie sur le clavier ?
Cette situation existe quand le processus-père capture les fichiers standard "stdin", "stdout" et "stderr" au travers de pipes créés par la fonction "CreatePipe(...)".
Les exemples que j'ai trouvés sur la toile ne résolvent pas ce problème car les entrées/sorties sont synchrones. Il me semble que pour le résoudre, il faudrait utiliser des entrées/sorties asynchrones un peu comme sous UNIX avec la fonction "select(...)" qui existe sous les API's mais ... seulement pour le sockets !...
J'ai regardé du côté des fonctions attachées à la fonction "CreateIoCompletionPort(...)" utilisant le drapeau "OVERLAPPED" combinées :
- d'une part, au travers des pipes créés avec la fonction "CreatePipe(...)"
- d'autre part, avec le fonctionnement des messages pour le graphique dans une boucle tournant sur la fonction "GetMessage(...)".
Comment articuler tout cela ?
4°) - Par quel moyen le processus-père peut-il forcer le processus-fils à effectuer des entrées/sorties NON bufferisées ?
J'ai bien essayé par le biais des héritages mais rien n'y a fait. Pourtant, "gdb" qui utilise cette méthode de pipe "pseudo-terminaux" y parvient parfaitement.
_______________________________________
En vous remerciant par avance pour votre aide.
Bien cordialement
Lou Papet
P.S. : Le schéma ci-dessous illustre ce je pensais faire pour faire cohabiter le graphique, les pipes et le dialogue. Mais est-ce bien correct dans l'esprit des API's ?
Solution trouvée à 3 questions sur 4 !...
Bonjour Andnotor et bonjour à Médinoc (pour la 4ème question),
Un grand merci pour avoir bien voulu répondre à mon appel.
Simplement pour découvrir l'utilisation des API's Windows, j'ai choisi de reprendre une petite application que j'avais proposée, sous LINUX, à la demande d'un professeur de mathématiques pour préfacer à l'époque des programmes écrits en fortran et/ou en Basic par ses élèves lors de travaux pratiques. J'en ai fait une description sur mon site "ICI". D'ailleurs, par la suite, une esquisse avait été commencée, malheureusement non concrétisée, suivant le même principe, pour un professeur de technologie, dans le but de préfacer des programmes d'élèves afin de piloter une petite fraiseuse à commandes numériques connectées avec une ligne série plutôt que de saisir manuellement des interminables commandes en G-code ISO sur un terminal Newburry connecté à la machine.
Citation:
1°) - Comment détecter dans le processus-père que le processus-fils n'existe plus ?
Effectivement, vous m'avez mis la puce à l'oreille en me suggérant que je libérais prématurément mes Handles et plus particulièrement, celui du PROCESS_INFORMATION. Désolé, j'avoue humblement être passé dessus à maintes reprises sans y prêter attention comme un débutant même si j'étais préoccupé à apprendre à me servir de ces API's et.... il y en a à apprendre !...
Comme vous me l'avez proposé, j'ai donc ouvert un thread supplémentaire qui ne contient qu'un appel à la fonction "WaitForSingleObject(process_info.hProcess, INFINITE)" suivi d'un drapeau d'alerte pour le programme processus-père. J'avais tenté d'utiliser cette fonction dans la boucle "GetMessage(...)" sans y parvenir.
D'ailleurs, petite réflexion toute personnelle, pourquoi les fonctions "WaitForSingleObject(..)" et "WaitForMultipleObjects(...)" avec un timeout de 0 ne retournent-elles pas un code du type par exemple "WAIT_CHILD_TERMINATED" ? On pourrait alors les utiliser dans la boucle "GetMessage()", beaucoup plus simplement, me semble-t-il, que de lancer un thread, solution qui ne doit pas être anodine au niveau du système.
Mais bon ... il faut faire avec !...
Citation:
2°) - Comment le processus-père peut-il forcer le processus-fils à terminer son exécution ?
En effet, la question rejoignait la première et le "TerminateProcess(process_info.hProcess, 9999)" s'est alors mis à bien fonctionner.
Vous dites que la fonction "TerminateProcess()" est brutale. Mais quand un met fin à l'activité d'un programme, c'est une action brutale. Renvoyant un code retour, elle me paraît moins brutale qu'un abort avec un code d'erreur. non ?
Est-elle proscrite par les développeurs des API's ?
Citation:
3°) - Comment programmer le dialogue processus-père <=> processus-fils pour que le processus-père sache que le processus-fils réclame une saisie sur le clavier ?
Effectivement, j'ai abandonné la méthode que j'avais trouvée sur la toile. J'ai scinder le dialogue en une fonction réception et une fonction transmission chacune dans deux threads différents qui se synchronisent tous seuls par le comportement de l'utilisateur.
Mon application comporte maintenant 4 threads :
- le thread du processus-père,
- le thread de réception des données en provenance du processus-fils
- le thread de transmission des données clavier vers le processus-fils
- le thread de surveillance de l'activité du processus-fils.
Elle a l'air de se comporter à peu près correctement, pour le moment tout au moins.
Reste la dernière question !...
Citation:
4°) - Par quel moyen le processus-père peut-il forcer le processus-fils à effectuer des entrées/sorties NON bufferisées ?
Le langage C, pour ne prendre que lui, emmagasine les données dans un buffer avant de les envoyer sur la console. Ceci me gêne car cela oblige les programmeurs, en C par exemple, à coder un "fflush(stdout)" avant chaque lecture ce que j'aurais bien aimé éviter.
Mais, il doit être néanmoins possible de forcer ces entrées/sorties car le debugger "gdb" y arrive si on debugue un programme C qui exécute plusieurs "printf" avant de lire sur le clavier.
Quand au logigramme, avec les dernières modifications, il s'est singulièrement simplifié, et dans la logique, et dans la réalisation.
Je vous renouvelle mes remerciements pour votre aide d'autant plus que je viens de faire un petit essai de curiosité.
Jusqu'à présent, je lançait la commande (les '_' étant des valeurs par défaut) :
ng_apiptgr _ _ _ _ _ _ lissajous_F
pour encapsuler le programme fortran de tracé de courbes de "Lissajous".
J'ai tenté la commande :
ng_apiptgr _ _ _ _ _ _ gdb --args lissajous_F
pour encapsuler le programme "gdb" qui encapsule à son tour le programme fortran "lissajous_F". Mon programme semble avoir bien réagi au premier abord en capturant les i/o du gdb. Cela me permettra peut-être de faire une petite évaluation sur la programmation d'un programme qui analyse le dialogue de "gdb" pour le rendre interactif avec les curses par exemple comme le font les produits UNIX "cgdb", "xdbx", "ddd".
Bien cordialement.
Lou Papet
Oui !... MsgWaitForMutipleObjects()
Bonsoir Médinoc,
Citation:
Envoyé par
Médinoc
Si tu veux attendre quelque chose dans ta boucle de messages, tu peux utiliser
MsgWaitForMutipleObjects(). Si ça retourne WAIT_OBJECT_0, c'est que c'est une fin de processus, si ça retourne WAIT_OBJECT_0+1 tu peux faire ton GetMessage()...
TerminateProcess() n'est pas proscrite, c'est ce que fait le Task Manager quand on tue un processus avec. TerminateThread() est proscrite par contre, parce que ça corrompt le reste du processus.
Merci encore pour votre réponse. En effet, j'avais regardé la fonction "MsgWaitForMutipleObjects()" que vous me signalez. Mais j'avais un peu buté sur la phrase
pHandles [in]
An array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types. It may not contain multiple copies of the same handle.
If one of these handles is closed while the wait is still pending, the function's behavior is undefined.
The handles must have the SYNCHRONIZE access right. For more information, see Standard Access Rights.
J'avais compris que si le processus-fils terminait normalement son exécution, le comportement de la fonction devenait indéfini donc imprévisible. Je n'avais donc pas trop insisté car je ne suis pas très affuté avec les API's que j'apprends depuis peu de temps.
Mais je vais approfondir cela très prochainement. Merci.
Lou Papet
Ah !... la commande numérique !...
Bonsoir Andnotor
Citation:
Envoyé par
Andnotor
J'avais moi-même créé un compilateur ISO complet pour commande numérique (des rectifieuses) il y a une vingtaine années ;)
Travailler autour des machines à commandes numériques était ma passion !... J'étais responsable, des années 1968 à 1972-73 de la programmation de la génération des surfaces de pâles d'hélicoptères en vue de la fabrication de leurs moules que je décris dans mon site " ICI ", ... si cela peut vous intéresser !.... (le lien "Les composites aéronautiques : 40 ans déjà !... n'existe plus !...) Par la suite, tout en étant responsable de la maintenance du système IBM VM/CMS, j'ai toujours gardé un contact avec la fabrication qui, assez souvent, demandait mon avis côté informatique, ce que j'appréciais beaucoup.
Citation:
Envoyé par
Andnotor
Un timeout autre que INFINITE entraînera un WAIT_TIMEOUT tant que le handle est encore valide, ce qui correspond d'une certaine façon à ton "WAIT_CHILD_TERMINATED".
J'ai remarqué que ce n'était pas tout à fait le cas car la fonction ne varie pas du code "WAIT_TIMEOUT", même quand le processus-fils disparaît. Mais peut-être que ma programmation était sûrement mauvaise !...
Médinoc m'a suggéré l'utilisation de la fonction "MsgWaitForMutipleObjects()" que j'avais regardé sans insistance et que je vais approfondir dès que possible. Pour le moment, ça baigne déjà pas mal, je peux continuer mon développement graphique avec optimisme !... Mais d'autres problèmes m'attendent au tournant, c'est sûr .....
Citation:
Envoyé par
Andnotor
Non, le thread secondaire ne consomme aucune ressource CPU puisque WaitForXXXObject est bloquant. Cette tâche ne fait qu'attendre ;)
Pour ce qui concerne la ressource CPU, j'entends bien, mais dans mon esprit de faisait plutôt allusion à la prise en charge par le système de la tâche dans toute la panoplie des phases de priorité, de mise en file d'attente d'exécution, d'éligibilité CPU, etc... que nous, nous ne percevons pas.
Citation:
Envoyé par
Andnotor
Prend une suite telle que LibreOffice, l'ouverture d'un fichier en écriture entraîne la création d'un fichier lock. A l'arrêt brutal du processus, le lock subsiste et le fichier reste verrouillé. Pas cool !
Par une demande d'arrêt, on laisse le temps à l'application de nettoyer ce qui doit l'être.
Après, je ne connais pas trop le C, je suis plutôt Delphi, et ne peux pas t'en dire plus sur ce sujet ;)
Mais le fichier "lock" de "LibreOffice" comme celui de "OpenOffice Writer" ou "Microsoft Word" permet surtout de générer des "Checkpoint" pour permettre une restauration à la reprise.
Dans ma carrière, ma hiérarchie m'a permis de travailler sur pas mal de machines qui m'ont conduit à programmer sous divers assembleurs, sous plusieurs langages comme l'Algol et le Basic au tout tout début, le Fortran, le Pascal, le PL/1, le C, le C++, puis à la retraite JAVA (pour applis sur mon téléphone mobile), mais je reviens toujours vers le langage C que je considère comme un assembleur évolué avec lequel on peut absolument tout faire, même de la programmation orientée objet (c'est plus un esprit qu'une programmation) comme c'est la mode aujourd'hui. Je dois confesser que, lorsqu'on m'avait imposé de travailler en C++, cela m'avait donné pas mal de boutons !...
Le dernier paragraphe était simplement une confidence sans grande importance.
Encore merci. Bien enrichissant.
Lou Papet
C'est tout bon... Message reçu !...
Bonjour Médinoc,
Bon pour l'argumentation. Je prends acte. J'essaierai très prochainement .... encore que, dans le principe, le thread qui attend la fin du processus-fils me convient puis que Andnotor m'affirme qu'un thread n'est pas lourd à gérer par le système. En effet, le système permet jusqu'à 64 threads simultanés. Cela invite à en user mais peut-être pas en abuser je suppose !...
Merci pour vos éclairages à tous les deux, j'ai pu gravir quelques marches !... Mon programme semble bien marcher au niveau de la gestion des échanges. J'ai d'autres petits problèmes plutôt liés à la programmation proprement-dite. Ils sont très peu bloquants.
Lou Papet