Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

Sujet : Récupération "au fil de l'eau" du résulat d'une commande DOS [ Windows / System ] (10MilleSabords)

jeudi 10 janvier 2008 à 15:11:14 | Récupération "au fil de l'eau" du résulat d'une commande DOS

10MilleSabords

Bonjour,

Tout est dans le sujet. Est-ce possible?
Voici ou j'en suis:
Je lance ma ligne de commande par un CreateProcess puis je récupère le résulat dans un buffer par un CreatePipe puis ReadFile.
Cela fonctionne très bien mais le buffer est rempli une fois que l'exécution dans la console est terminée or j'aimerai pouvoir récupérer les informations au fil de l'exécution de la commande.
Quelqu'un a-t-il déjà fait ca?
Merci d'avance pour votre aide.
Voici mon code:

STARTUPINFO si;
 PROCESS_INFORMATION pi;
 unsigned long dwExitCode;


 HANDLE PipeInputRead;
 HANDLE PipeInputWrite;
 HANDLE PipeOutputRead;
 HANDLE PipeOutputWrite;

 SECURITY_ATTRIBUTES securityattribs = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};
 
 DWORD dwRead;
 DWORD NumByte;
 char buffer[BUFSIZE]; 

 memset(&si, 0, sizeof(si));
 memset(&pi, 0, sizeof(pi));
 si.cb = sizeof(si);

 // Create pipe for standard output redirection
 CreatePipe(&PipeOutputRead, &PipeOutputWrite, &securityattribs, 0);
 // Create pipe for standard input redirection.
 CreatePipe(&PipeInputRead, &PipeInputWrite, &securityattribs, 0);

 si.dwFlags = STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES;
 si.hStdInput = PipeInputRead;
 si.hStdOutput = PipeOutputWrite;
 si.hStdError = PipeOutputWrite;
 si.wShowWindow = SW_SHOW;

 bool pSuccess = CreateProcess( NULL,"C:\\_prov\\avr prog\\AVROSP.exe -dATmega128 -e" , NULL, NULL, true, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

 if (pSuccess)
 {
  CloseHandle(pi.hThread); // fermer le handle de thread dès qu'il devient inutile
  WaitForSingleObject(pi.hProcess, INFINITE); // attente jusqu'à la signalisation de la fermeture
  GetExitCodeProcess(pi.hProcess, &dwExitCode); // le processus notepad est terminé
  if (dwExitCode != STILL_ACTIVE)
   CloseHandle(pi.hProcess); // fermer le handle de process
 }
 else
 {
  CloseHandle(PipeOutputWrite);
  CloseHandle(PipeInputRead);
 }
 
 CloseHandle(PipeOutputWrite);
 CloseHandle(PipeInputRead);
 CloseHandle(PipeInputWrite);

 while (ReadFile(PipeOutputRead, buffer, BUFSIZE-1, &dwRead, NULL) && (dwRead != 0))
 {
  buffer[dwRead] = '\0';  
 }
    SetDlgItemText(Handle,IDC_EDIT1,buffer); // Affichage dans la ComboBox
 

 CloseHandle(PipeOutputRead);


vendredi 11 janvier 2008 à 12:48:42 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

rt15

Membre Club Administrateur CodeS-SourceS
Salut,

Bah là j'ai pas le temps de coder, mais voilà ce que tu peux essayer :

Tu lis le pipe après que le processus soit terminé tout à fait volontairement avec ton WaitForSingleObject.

D'après l'aide du pipe, cela ne devrait pas poser de problème de faire des Read avant la fin du processus.

Je verrais donc une boucle dans ce genre là :

while (WaitForSingleObject(pi.hProcess, 1) == WAIT_TIMEOUT)
{
  Read...
}
Read...

Comme ça, toute les millisecondes, tu lis la sortie et tu vérifie que le programme ne s'est pas terminé.


vendredi 11 janvier 2008 à 14:42:16 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

rt15

Membre Club Administrateur CodeS-SourceS
Ca à l'air presque bon, mais ça bloque sur le dernier Read. Le pipe est encore là (Donc pas d'erreur), la fin n'est pas atteinte... Read attend des nouvelles entrées...

Voilou une appli qui fait un ping dans une nouvelle fenêtre mais qui fait sa sortie sur la première :
#include "windows.h"

#define BUFSIZE 256

void ReadPipe(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;

while (ReadFile(hPipeRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) && nBytesRead)
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL);
}

int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL pSuccess;

HANDLE PipeInputRead;
HANDLE PipeInputWrite;
HANDLE PipeOutputRead;
HANDLE PipeOutputWrite;

SECURITY_ATTRIBUTES securityattribs = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};

CreatePipe(&PipeOutputRead, &PipeOutputWrite, &securityattribs, 0);
CreatePipe(&PipeInputRead, &PipeInputWrite, &securityattribs, 0);

memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = PipeInputRead;
si.hStdOutput = PipeOutputWrite;
si.hStdError = PipeOutputWrite;
si.wShowWindow = SW_SHOW;

pSuccess = CreateProcess(NULL, "ping 127.0.0.1" , NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

if (pSuccess)
{
while (WaitForSingleObject(pi.hProcess, 1) == WAIT_TIMEOUT)
{
ReadPipe(PipeOutputRead);
}
ReadPipe(PipeOutputRead);
}

CloseHandle(PipeInputRead);
CloseHandle(PipeInputWrite);
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);

return 0;
}


vendredi 11 janvier 2008 à 14:44:20 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

rt15

Membre Club Administrateur CodeS-SourceS
J'oubliais : c'est une application console bien sûr.

Pour passer le dernier Read, il faudrait peut être faire un thread qui attend la fin du processus avec WaitForSingleObject (Avec INFINITE), et qui ferme le handle du pipe.


vendredi 11 janvier 2008 à 15:07:35 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

10MilleSabords

Merci rt15 pour ta réponse!

J'avais effectivement pensé à la lecture dans une boucle d'attente mais je n'avais pas approfondit.
J'ai testé et ça s'exécute bien mais je pense en fait que j'ai 2 problèmes à régler car le but final est d'afficher ces résultats dans une EditBox (Appli windows)
1) Récupérer les résultats au fil de l'eau: je pense que ta solution résoud ce problème
2) Afficher au fil de l'eau dans l'EditBox: Et là ça se complique car la fenêtre se raffraichit une fois l'exécution de la console terminée
J'utilise  SetDlgItemText dans la boucle pour raffraichir.

Merci encore, ça m'a décoincer pas mal!

vendredi 11 janvier 2008 à 15:38:37 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

rt15

Membre Club Administrateur CodeS-SourceS
Tu peux passer par des threads.
J'en ai fait un pour corriger le bug cité plus haut.

Il faudrat que tu en fasse un deuxième qui attende la fin du processus pour tuer le premier thread.

#include "windows.h"
#include "stdlib.h"

#define BUFSIZE 256

typedef struct _ReadPipeThreadParam
{
 HANDLE hPipe;
} ReadPipeThreadParam;

DWORD __stdcall ReadPipe(ReadPipeThreadParam* param)
{
 CHAR lpBuffer[256];
 DWORD nBytesRead;
 DWORD nCharsWritten;

 while (ReadFile(param->hPipe, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) && nBytesRead)
  WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nBytesRead, &nCharsWritten, NULL);
 return 0;
}

int main()
{
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 BOOL pSuccess;
 ReadPipeThreadParam param;
 DWORD nThreadId;
 HANDLE hThread;

 HANDLE PipeInputRead;
 HANDLE PipeInputWrite;
 HANDLE PipeOutputRead;
 HANDLE PipeOutputWrite;

 SECURITY_ATTRIBUTES securityattribs = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};

 CreatePipe(&PipeOutputRead, &PipeOutputWrite, &securityattribs, 0);
 CreatePipe(&PipeInputRead, &PipeInputWrite, &securityattribs, 0);

 memset(&si, 0, sizeof(si));
 si.cb = sizeof(si);
 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
 si.hStdInput = PipeInputRead;
 si.hStdOutput = PipeOutputWrite;
 si.hStdError = PipeOutputWrite;
 si.wShowWindow = SW_SHOW;

 pSuccess = CreateProcess(NULL, "ping 127.0.0.1" , NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);


 if (pSuccess)
 {
  param.hPipe = PipeOutputRead;
  hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ReadPipe, &param, 0, &nThreadId);
 
  WaitForSingleObject(pi.hProcess, INFINITE);
  TerminateThread(hThread, 0);
 }
 
 CloseHandle(hThread);
 CloseHandle(PipeInputRead);
 CloseHandle(PipeInputWrite);
 CloseHandle(PipeOutputWrite);
 CloseHandle(PipeOutputRead);

 system("pause");

 return 0;
}


vendredi 11 janvier 2008 à 16:12:45 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

10MilleSabords

Effectivement je n'avais pas pensé aux threads, je vais testé ça...
Merci.

vendredi 11 janvier 2008 à 17:14:19 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

10MilleSabords

J'ai pu testé les threads grâce à ton code et à l'exécution le résultat est le même: l'affichage parvient une fois l'exécution de la console terminée.
En fait, j'ai pu vérifier que la thread récupère bien les résultats en parallèle de l'exécution de la console mais l'affichage n'arrive qu'à la fin.
D'autre part, j'ai compté le nombre de fois que je vais dans la boucle du ReadFile (= nbre de fois qu'il vient récupérer des caractères dans la console): 2 fois! alors qu'il faudrait plusieurs 10n de fois pour être réellement au fil de l'eau...
Ca veut donc dire que le temps d'exécution du ReadFile est bien trop longue pour récupérer véritablement au fil de l'eau (en même temps, je suis sous windows et pas un OS temps réel!)
Je crains que je vais me contenter de l'affichage en fin d'exécution....


samedi 12 janvier 2008 à 22:31:58 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

rt15

Membre Club Administrateur CodeS-SourceS
Bah pour un ping, on les voit bien arriver les uns après les autres.
Voilà une appli avec un champ de texte où on peut entrer des commandes, et un champ de texte où les résultats sont affichés.

#include "windows.h"

#define BUFFER_SIZE 65536

HINSTANCE _hThisInstance; // Handle du module
HWND _hWnd; // Handle de la fenêtre
HWND _hInput; // Handle de l'EDIT où l'utilisateur tape les commandes
HWND _hOutput; // Handle de l'EDIT où la sortie de la console est affichée
LPSTR _lpAppName = "ConsoleInWindow"; // Nom de l'appli
HANDLE _hConsole; // Handle de l'appli lancée
CHAR lpPipeContent[BUFFER_SIZE]; // Contenu du pipe


HANDLE hReadPipe; // Thread de lecture du pipe
HANDLE hClosePipe; // Thread qui détruit le thread de lecture

// Les Pipe de lecture et d'écriture fournis à la console
HANDLE hPipeInputRead;
HANDLE hPipeInputWrite;
HANDLE hPipeOutputRead;
HANDLE hPipeOutputWrite;

//
// Affiche le message d'erreur associé à la dernière
// erreur Win32 et ferme l'appli.
//
void ShowLastError()
{
DWORD nLastError;
LPSTR lpMessageBuffer;

// Récupération du numéro de l'erreur
nLastError = GetLastError();

// Formatage du message
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMessageBuffer, 0, NULL);

// Affichage du message et fin de l'appli
MessageBox(NULL, lpMessageBuffer, "ERROR", MB_OK | MB_ICONERROR);
ExitProcess(nLastError);
}

//
// Détruit le thread de lecture dès que la console est fermée.
//
DWORD __stdcall ClosePipe(LPVOID null)
{
WaitForSingleObject(_hConsole, INFINITE);
TerminateThread(hReadPipe, 0);

CloseHandle(hPipeInputRead);
CloseHandle(hPipeInputWrite);
CloseHandle(hPipeOutputWrite);
CloseHandle(hPipeOutputRead);

CloseHandle(hReadPipe);
CloseHandle(hClosePipe);
return 0;
}

//
// Lit le contenu du pipe et le copie dans la fenêtre.
//
DWORD __stdcall ReadPipe(HANDLE hPipe)
{
CHAR* lpCurrentPos; // Position courante de l'écriture dans le buffer
DWORD nBytesRead; // Nombre d'octets lus dans le pipe

// On va concaténer
lpCurrentPos = lpPipeContent;

// Lecture du pipe
while (ReadFile(hPipe, lpCurrentPos, BUFFER_SIZE - 1, &nBytesRead, NULL) && nBytesRead)
{
// Mise en place du zéro terminal
lpCurrentPos[nBytesRead - 1] = '\0';
SetWindowText(_hOutput, lpPipeContent);

// On va concaténer la suite au niveau du zéro terminal
lpCurrentPos = lpCurrentPos + nBytesRead - 1;
}

return 0;
}

//
// Lance la commande demandée.
//
void Execute(CHAR* lpCommandLine)
{
STARTUPINFO si; // Info de lancement du processus
PROCESS_INFORMATION pi; // Récupération d'handles sur le processus lancé
DWORD nThreadId; // Récupération du thread ID lors des créations de thread

SECURITY_ATTRIBUTES securityattribs = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};

if (! CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &securityattribs, 0)) ShowLastError();
if (! CreatePipe(&hPipeInputRead, &hPipeInputWrite, &securityattribs, 0)) ShowLastError();

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = hPipeInputRead;
si.hStdOutput = hPipeOutputWrite;
si.hStdError = hPipeOutputWrite;
si.wShowWindow = SW_SHOW;

if (CreateProcess(NULL, lpCommandLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
// Lancement du thread de lecture du pipe
hReadPipe = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ReadPipe, hPipeOutputRead, 0, &nThreadId);

// Lancement du thread qui va tuer le thread de lecture
_hConsole = pi.hProcess;
hClosePipe = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ClosePipe, NULL, 0, &nThreadId);
}
}

//
// Traitement des messages.
//
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
RECT rect; // Récupération de la taille de la cliente pour redimenssionner les contrôles

switch (nMessage)
{
case WM_MOVE:
case WM_ACTIVATE:
case WM_SIZING:
GetClientRect(_hWnd, &rect);
SetWindowPos(_hInput, 0, 0, rect.bottom - 20, rect.right, 20, SWP_NOZORDER);
SetWindowPos(_hOutput, 0, 0, 0, rect.right, rect.bottom - 20, SWP_NOZORDER);
return DefWindowProc(hWnd, nMessage, wParam, lParam);
case WM_DESTROY:
// On signale que le thread va s'arrêter
PostQuitMessage(0);
break;
default:
// Application du traitement par défaut
return DefWindowProc(hWnd, nMessage, wParam, lParam);
}
return 0;
}

//
// Initialise la fenêtre principale de l'appli.
//
void InitWindow()
{
WNDCLASSEX wincl; // Classe de la fenêtre utilisée

// Création de la classe de fenêtre
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.style = CS_OWNDC;
wincl.lpfnWndProc = WindowProcedure;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hInstance = _hThisInstance;
wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
wincl.lpszMenuName = 0;
wincl.lpszClassName = _lpAppName;
wincl.hIconSm = NULL;

// Enregistrement de la classe
if (!RegisterClassEx(&wincl)) ShowLastError();

// Création de la fenêtre
_hWnd = CreateWindowEx(0, _lpAppName, _lpAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, HWND_DESKTOP, NULL, _hThisInstance, NULL);
_hInput = CreateWindowEx(0, "EDIT", "ping 127.0.0.1", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 0, 0, 0, _hWnd, NULL, _hThisInstance, NULL);
_hOutput = CreateWindowEx(0, "EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_READONLY | ES_OEMCONVERT, 0, 0, 0, 0, _hWnd, NULL, _hThisInstance, NULL);

ShowWindow(_hWnd, SW_SHOW);
}

#pragma comment(linker, "/entry:main")
INT32 _cdecl main()
{
MSG message; // Réception des messages envoyés à l'application
CHAR lpCommandLine[1024]; // Rédaction de la commande à executé
CHAR lpInputContent[1024]; // Récupération de la commande tapée par l'utilisateur

// Récupération du handle du module
_hThisInstance = GetModuleHandle(NULL);

InitWindow();

// Boucle de traitement des messages
while (GetMessage(&message, NULL, 0, 0))
{
// On execute la commande lors d'un appui sur entrée
if (((message.hwnd == _hInput) || (message.hwnd == _hOutput)) && (message.wParam == VK_RETURN) && (message.message == WM_KEYUP))
{
SendMessage(_hInput, WM_GETTEXT, 1024, (LPARAM)lpInputContent);
wsprintf(lpCommandLine, "cmd /C \"%s\"", lpInputContent);
Execute(lpCommandLine);
}

// Traduit certains messages
TranslateMessage(&message);

// Distribution des messages aux fenêtres
DispatchMessage(&message);
}

// Code d'erreur en sortie
return message.wParam;
}


lundi 14 janvier 2008 à 10:20:12 | Re : Récupération "au fil de l'eau" du résulat d'une commande DOS

10MilleSabords

Ouah! Encore merci de consacrer de ton temps à mon problème!

Effectivement ton appli fonctionne très bien, le ping remonte bien au fur et à mesure.
J'ai testé ma ligne de commande avec mon programme DOS et là, bizarrement le résultats ne remontent qu'une fois le programme terminé.
En fait, ce programme DOS programme un microcontroleur (je suis électronicien à la base) et renvoie un état d'avancement au fur et mesure.
En bref, je n'observe pas le même comportement entre le ping et mon programme dos.
Peut-être un problème de priorité car le programme dos prend peut-être plus de ressources pendant la programmation et ne permet pas à l'affichage de s'exécuter.



1 2

Cette discussion est classé dans : buffer, handle, pi, closehandle, pipeoutputwrite


Répondre à ce message

Sujets en rapport avec ce message

getoenfilename -> ??? [ par stefbuet ] salut,sur une source (http://www.cppfrance.com/code.aspx?ID=28478)j'ai extrait une fonction de la librairy créé et ais essayé de la faire fonctioner, Pipes sous windows [ par ssmint ] Bonjour à tous, Voilà je voudrais piloter CMD.EXE gràce à mon prog pour au final pouvoir réaliser une sorte de telnet...J'ai redirigé l'entrée et la s Redirection sortie [ par M5i9k ] Bonjour à tous,je voudrais lire la sortie d'une console lancée à partir de mon programme (j'utilise CreateProcess), je voudrais savoir si je suis sur CreateProcess et processus infini [ par Rankin ] Salut à tous,Je suis en train de développer une appli qui lance pas mal de commandes système pour récupérer notamment la configuration du réseau. Pour Comment utiliser un buffer [ par sofoot ] Bonjour,Je travail sous C++Builder 6 et je souhaite faire communiquer un système (un monnayeur) avec mon pc via un port COM. Afin de récupérer les inf Obtenir l'handle d'une DLL [ par TryToHelpMe ] Bonjour,J'ai un nouveau problème que je n'arrive pas à résoudre.J'ai besoin de récupérer l'handle de ma DLL.Je fait appel à ma DLL depuis un programme Problème création handle [ par nicolasmaicheul ] Bonjour,Cette simple ligne :string^ s = gcnew string("test");provoques ces ereurs à la compilation (visual c++ express) :error C3193: '^'*: requiert l [Maple]Problème Tracé de champ magnétique [ par Nethernat ] Bonjour à tous, à vrai dire je ne sais pas très bien où placer ce post ... J'essaye de tracer les lignes de champ magnétique crées par une spire de Info sur les include [ par jose12 ] Bonjour, contexte : Je ne suis pas développeur mais admin réseau. Je connais un peu le VB et divers langage Web, et j'ai une vision très très succint Double buffer win32 [ par Stepharcher ] Bonjour à tous !J'ai récemment tenté le double buffer sous window avec GDI... Mais je ne comprend pas trop mon erreur. Quand je dessine directement su


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,530 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.