Page 1 sur 1

Décoder les flux standards sous windows (stdin et stdout)

Publié : sam. 02/mai/2020 9:27
par Naheulf
Bonjour,
J'essaye de faire un programme qui prend des données textuelles sur l'entrée standard, fait un traitement dessus, puis recrache le résultat sur la sortie standard.
Une version simplifiée du programme donnerais quelque chose du genre :

Code : Tout sélectionner

If OpenConsole("", )
	Define Text$ = Input()
	While Text$ <> #PB_Input_Eof
		Text$ = UCase(Text$)
		PrintN(Text$)
		Text$ = Input()
	Wend 
EndIf
Si j'exécute directement le programme et que saisi des choses dans la console qui s'affiche j’obtiens bien le résultat escompté.

En revanche, si j'essaye de relier l'entrée du programme à la sortie d'un autre via un pipe ça fait juste n'importe quoi.
Pour tester j'utilise la commande suivante :

Code : Tout sélectionner

ping 127.0.0.1 | monprogramme.exe
La sortie normale de la commande ping est :

Code : Tout sélectionner

Envoi d'une requête 'Ping'  127.0.0.1 avec 32 octets de données :
Réponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
Réponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
Réponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
Réponse de 127.0.0.1 : octets=32 temps<1ms TTL=128

Statistiques Ping pour 127.0.0.1:
    Paquets : envoyés = 4, reçus = 4, perdus = 0 (perte 0%),
Durée approximative des boucles en millisecondes :
    Minimum = 0ms, Maximum = 0ms, Moyenne = 0ms
sauf qu'après passage dans mon programme j'ai ce truc :

Code : Tout sélectionner

??????????????┼????????´????????????????????Q>????´????????????????????????´????????????????????
????´????????????????????????´????????????????????????????┼??????????????????????%??????????????
??????????????????┼┼??????????????????????
Si quelqu'un à une idée de comment régler le problème, je suis preneur.

Note :
J'ai essayé de combiner ReadConsoleData(), PeekS() et PokeS() de différentes façons, je n'arrive jamais à avoir un résultat qui conserve tous les caractères.

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : sam. 02/mai/2020 9:34
par Ar-S
Ce n'est pas une histoire d'unicode, #PB_UTF8 etc avec ton openconsole et ton exe ? (avec les flag #PB_Unicode , #PB_UTF8 etc) ?

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : sam. 02/mai/2020 9:51
par Naheulf
Bah j'ai testé mais j'ai pas réussi.

Le plus proche que j'ai réussi à faire c'est avec un code du genre :

Code : Tout sélectionner

If OpenConsole("")
	#BUFFER_SIZE = 1024
	*Buffer = AllocateMemory(#BUFFER_SIZE)
	ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
	While ReadSize
		Text$ = PeekS(*Buffer, ReadSize, #PB_Ascii)
		Text$ = UCase(Text$)
		PrintN(Text$)
		ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
	Wend 
EndIf
Sauf que ça ne garde pas non plus tous les caractères... (mais dans ce cas, on est cohérent entre une exécution direct et un exécution avec des pipes)
Le texte :

Code : Tout sélectionner

Je me creuse la tête.
Donne :

Code : Tout sélectionner

JE ME CREUSE LA T^TE.

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : sam. 02/mai/2020 10:46
par GallyHC

Code : Tout sélectionner

If OpenConsole("")
   #BUFFER_SIZE = 1024
   *Buffer = AllocateMemory(#BUFFER_SIZE)
   ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
   While ReadSize
      Text$ = PeekS(*Buffer, ReadSize, #PB_Ascii)
      ;Text$ = UCase(Text$)
      PrintN(Text$)
      ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
   Wend
EndIf

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : sam. 02/mai/2020 11:52
par Naheulf
En fait t'as juste commenté la partie "utile" du code (la fonction UCase() qui représente le traitement que doit faire le programme).
Le cœur du problème reste intact : certains caractères ne sont pas conservés (ex : "ê" devient "^", UCase ou non). Donc si ces caractères visibles deviennent n'importe quoi, je n'ose imaginer ce qu'il se passera sur les caractères de contrôles (dont le traitement est le but du programme complet).

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : sam. 02/mai/2020 19:40
par Kwai chang caine
Je ne sais pas si c'est ce que tu cherches car c'est juste pour windows, :oops:
Mais y'a ce code de ZORRO qui marche sous W10, j'ai vérifié :wink:
http://www.purebasic.fr/french/viewtopi ... 93#p192393

Code : Tout sélectionner

prg=RunProgram("cmd.exe", "/c ipconfig /all  ", "", #PB_Program_Open|#PB_Program_Read) ; la commande "ipconfig /all" est entré dans la console
If prg
      While ProgramRunning(prg)
            If AvailableProgramOutput(prg)
                  sOEM_in_unicode.s = ReadProgramString(prg, #PB_Ascii)
                  iByteLength = Len(sOEM_in_unicode) + 2
                  sOem_in_Ascii.s = Space(iByteLength)
                  PokeS(@sOem_in_Ascii, sOEM_in_unicode, -1, #PB_Ascii)
                  sUnicode.s = Space(iByteLength)
                  OemToChar_(@sOem_in_Ascii, @sUnicode)
                  Sortie$=Sortie$+sUnicode.s+Chr(10)+Chr(13)
            EndIf
      Wend
      Sortie$ + Chr(10) + Chr(13)
      Sortie$ + "Code de retour : " + Str(ProgramExitCode(prg))      
      
      CloseProgram(prg) ; Ferme la connection vers le programme
EndIf
MessageRequester("Sortie", Sortie$)
qui donne
Console a écrit :
Utilisation : ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]

[-r count] [-s count] [[-j host-list] | [-k host-list]]

[-w timeout] [-R] [-S srcaddr] [-c compartment] [-p]

[-4] [-6] nom_cible


Options :

-t Effectue un test ping sur l'hôte spécifié jusqu'à son arrêt.

Pour afficher les statistiques et continuer,

appuyez sur Ctrl+Attn.

Pour arrêter, appuyez sur Ctrl+C.

-a Résout les adresses en noms d'hôtes.

-n count Nombre de demandes d'écho à envoyer.

-l size Taille du tampon d'envoi.

-f Active l'indicateur Ne pas fragmenter dans le paquet (IPv4

uniquement).

-i TTL Durée de vie.

-v TOS Type de service (IPv4 uniquement. La

configuration de ce paramètre n'a aucun effet sur le type

de service dans l'en-tête IP).

-r count Itinéraire d'enregistrement du nombre de sauts (IPv4

uniquement).

-s count Horodatage du nombre de sauts (IPv4 uniquement).

-j host-list Itinéraire source libre parmi la liste d'hôtes (IPv4

uniquement).

-k host-list Itinéraire source strict parmi la liste d'hôtes (IPv4

uniquement).

-w timeout Délai d'attente pour chaque réponse, en millisecondes.

-R Utilise l'en-tête de routage pour tester également

l'itinéraire inverse (IPv6 uniquement).

D'après la RFC 5095, l'utilisation de cet en-tête de routage

est déconseillée. Certains systèmes peuvent supprimer des

demandes d'écho si cet en-tête est utilisé.

-S srcaddr Adresse source à utiliser.

-c compartment Identificateur de compartiment de routage.

-p Effectue un test ping sur l'adresse de fournisseur

de la virtualisation réseau Hyper-V.

-4 Force l'utilisation d'IPv4.

-6 Force l'utilisation d'IPv6.



Code de retour : 1

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : dim. 03/mai/2020 9:00
par Naheulf
Merci Kwai chang caine.

Gally m'as donné une solution sur discord et j'ai oublié de faire le retour sur le fofo :oops:

En fait tu lis dans mes pensées. Ta solution (enfin celle de Zorro) ne correspond pas à ce que je voulais faire pour ce programme : elle correspond à ce que je voulais faire pour une seconde variante du programme (qui utiliserait effectivement l'appel à un sous programme)

Reste à voir si je vais avoir le droit à d'autres "surprises" comme le caractère de contrôle "ESC" qui se transforme en '←' avec OemToCharW()...

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : dim. 03/mai/2020 12:24
par TazNormand
@Naheulf : peux-tu poster ici la solution que t'a donné GallyHC sur Discord, car elle pourrait servir à quelqu'un d'autre plus tard. Merci

Re: Décoder les flux standards sous windows (stdin et stdout

Publié : dim. 03/mai/2020 15:06
par GallyHC
Voila:

Code : Tout sélectionner

If OpenConsole("", #PB_Ascii)
  #BUFFER_SIZE = 1024
  Text$ = Space(#BUFFER_SIZE)
  *Buffer  = AllocateMemory(#BUFFER_SIZE)
  ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
  While ReadSize
    OemToChar_(*Buffer, @Text$)
    PrintN((Mid(Text$, 1, ReadSize - 2)))
    ReadSize = ReadConsoleData(*Buffer, #BUFFER_SIZE)
  Wend
EndIf