[Borland C++ builder] Redirection sdtout

Redirection sdtout [Borland C++ builder] - Programmation

Marsh Posté le 06-06-2001 à 17:18:22    

J'ai trouvé comment rediriger stdout
quasiment comme je le voulais (Je suis sous
Borland c++ 4.0)
Voilà, cela marche mais j'aimerais que cela marche légèrement différement...
En effet, lorsque je lance ma commande, je suis obligé d'attendre que cette
commande soit terminée pour que le résultat s'affiche dans mon Memo... De
plus, tous le temps de la commande, l'application est comme "bloquée",
impossible de déplacer la fenêtre par exemple...
Si qq un peu m'aider, cela serait vraiment sympa... Merci d'avance !
Voici mon code :
(précision, Rippack_RipFormBeta->Memo1 est le mémo dans lequel je sort,
filepos est ma ligne de commande)
 

Code :
  1. Rippack_RipFormBeta->Memo1->Clear();
  2. int FBreak;
  3. HANDLE hReadPipe;
  4. HANDLE hWritePipe;
  5. STARTUPINFO si;
  6. LPSECURITY_ATTRIBUTES lpsa = NULL;
  7. if(CreatePipe(&hReadPipe,&hWritePipe,lpsa,0))
  8. {
  9.   memset(&si, 0, sizeof(STARTUPINFO));
  10.   si.cb = sizeof(STARTUPINFO);
  11.   si.dwFlags = STARTF_USESHOWWINDOW |STARTF_USESTDHANDLES;
  12.   si.wShowWindow = SW_HIDE;
  13.   si.hStdOutput = hWritePipe;
  14.   si.hStdError = hWritePipe;
  15.   PROCESS_INFORMATION pi;
  16.   if(hWritePipe)
  17.   {
  18.     Rippack_RipFormBeta->Memo1->Lines->Add("Working..." );
  19.     Application->ProcessMessages();
  20.     if(CreateProcess(NULL,filepos.c_str(),NULL,NULL,TRUE,0,0,0,&si,&pi))
  21.     {
  22.       CloseHandle(pi.hThread);
  23.       WaitForSingleObject(pi.hProcess, 90000);
  24.       if(hReadPipe)
  25.       {
  26.         DWORD BytesRead; //unsigned long
  27.         char dest[4000];
  28.         bool RdLoopDone = false;
  29.         Rippack_RipFormBeta->Memo1->Clear();
  30.         FBreak = 1;
  31.         if(ExitCode) Screen->Cursor = crDefault;
  32.         while(!RdLoopDone)
  33.         {
  34.           memset(dest, 0, 4000);
  35.           if(ReadFile(hReadPipe, &dest, sizeof(dest), &BytesRead,
  36. NULL))
  37.           {
  38.             Rippack_RipFormBeta->Memo1->Lines->Add(String(dest));
  39.             if(BytesRead < 4000) RdLoopDone = true;
  40.             if(FBreak > 150) RdLoopDone = true;
  41.             FBreak++;
  42.             CloseHandle(hReadPipe);
  43.             CloseHandle(hWritePipe);
  44.             CloseHandle(pi.hProcess);
  45.           }
  46.         }
  47.       }
  48.     }
  49.   }
  50. }
 

[edit]--Message édité par bruce--[/edit]


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 17:18:22   

Reply

Marsh Posté le 06-06-2001 à 17:33:08    

oui, c'est normal... je me suis fait avoir de la meme facon...

Citation :


ReadFile returns when one of the following is true: a write operation completes on the write end of the pipe, the number of bytes requested has been read, or an error occurs.


c'est a dire que tant que tu n'ecris rien, ca ne "revient" pas et donc ton prog. est bloqué..
l'astuce (merci minicooler :jap: ) est d'utiliser l'API PeekNamedPipe pour savoir si il y a qqchose d'ecrit et si c'est le cas, utiliser ReadFile pour recuperer le contenu !


---------------
www.alliancefrancophone.org ... Home is where the heart is
Reply

Marsh Posté le 06-06-2001 à 17:38:05    

Heu... tu n'aurrai pas un exemple de code qq part car je suis pas encore bien pro en prog... J'ai pompé ça sur un exemple fourni avec BC++ en adaptant à mes besoins...
 
Merci encore ! :)


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:00:34    

beuh... j'fais du Delphi, moi...  mais je vais essayer de te trouver un bout de code relativement clair...


---------------
www.alliancefrancophone.org ... Home is where the heart is
Reply

Marsh Posté le 06-06-2001 à 18:05:22    

Code :
  1. procedure TProcess.ReadScreen;
  2. var
  3.   Buffer: array[0..255] of Char;
  4.   dwLeft, dwRead : DWORD;
  5. begin
  6. //  FillChar(Buffer, SizeOf(Buffer), 0);
  7.   dwLeft := 0;
  8.   dwRead := 0;
  9.   FLastLines := '';
  10.   PeekNamedPipe (hOutPipeRead, nil, 0, @dwRead, @dwLeft, nil);
  11.   // has anything been read?
  12.   if (dwLeft <> 0) then
  13.   begin
  14.     ReadFile(hOutPipeRead, Buffer, dwLeft, dwRead, nil);
  15.     // finish buffer to PChar
  16.     Buffer[dwRead] := #0;
  17.     // combine the buffer with the rest of the last run
  18.     FLastLines := Buffer;
  19.     FLines := FLines + Buffer ;
  20.   end;
  21. end;


---------------
www.alliancefrancophone.org ... Home is where the heart is
Reply

Marsh Posté le 06-06-2001 à 18:13:37    

Heu... bon, je doit avouer avoir du mal à piger ta syntaxe... Le pascal est qd même légèrement différent... :)


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:26:10    

pour éviter que ça bloque il faut faire régulièrement des Application->ProcessMessages(); c'est-à dire juste après le memo->lines->add.
Peut-être que ça résoudra l'autre problème en même temps...

 

[edit]--Message édité par antp--[/edit]


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:27:15    

Pas con, je vais essayer.


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:29:08    

si tu le met juste après le ->add il risque de pas le faire souvent pour les longues opérations
si tu le met dans la boucle en dehors du if c'est dangereux pcq ton appli risque de prendre trop de CPU pour rafraichir... il faut tester


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:32:48    

m'etonnerait que ca marche... c'est l'appel de l'API qui est bloquant... le ProcessMessage ne resoudra rien, je pense ...
 
sinon, regarde l'aide de l'API PeekNamedPipe, la declaration en C + le code Delphi devrait pouvoir t'aider a faire la conversion .


---------------
www.alliancefrancophone.org ... Home is where the heart is
Reply

Marsh Posté le 06-06-2001 à 18:32:48   

Reply

Marsh Posté le 06-06-2001 à 18:35:56    

ha ouais c'est au WaitForSingleObject(pi.hProcess, 90000); qu'il bloque... j'avais pas vu.
le plus simple serait alors de le mettre dans un thread séparé je crois.


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:39:58    

ou alors:
while(!WaitForSingleObject(pi.hProcess, 1000))
{
  Application->ProcessMessages();
}
 
toutes les secondes il fait le processmessages.
je sais pas si c'est très bien comme solution.
et si le programme exécuté est calé il attend indéfiniment.


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:40:03    

antp a écrit a écrit :

ha ouais c'est au WaitForSingleObject(pi.hProcess, 90000); qu'il bloque... j'avais pas vu.
le plus simple serait alors de le mettre dans un thread séparé je crois.




 
un thread séparé, c le truc à faire en effet...

Reply

Marsh Posté le 06-06-2001 à 18:41:38    

Heu... en Win32 j'ai du mal, un exemple de code ???


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:42:45    

pourquoi en win32 ? y a des objets pour faire des threads dans C++builder, c'est plus simple à utiliser je crois.


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:44:29    

Hummm... disons que je m'y connais mal ;)


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:45:55    

bruce a écrit a écrit :

Hummm... disons que je m'y connais mal ;)




 
DWORD threadid;
HANDLE threadhandle;
 
...
threadhandle = CreateThread(NULL,1024,ma_fonction,NULL,CREATE_SUSPENDED,&threadid);
...
TerminateThread(threadhandle,0);
 
==================
 
 
DWORD WINAPI ma_fonction(LPVOID)
{
       EnterCriticalSection(&crit);
 
       // ... travail ...
 
       LeaveCriticalSection(&crit);
      return 0;
}

Reply

Marsh Posté le 06-06-2001 à 18:48:08    

robripper a écrit a écrit :

 
 
DWORD threadid;
HANDLE threadhandle;
 
...
threadhandle = CreateThread(NULL,1024,ma_fonction,NULL,CREATE_SUSPENDED,&threadid);
...
TerminateThread(threadhandle,0);
 




 
y a aussi la classe TThread.
Moi j'utiliserais celle-ci, ça a l'air plus simple :)

 

[edit]--Message édité par antp--[/edit]


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:48:11    

Hu ?  :??:


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 18:48:26    

Tu peux aussi modifier les priorités ...
 
SetThreadPriority(threadhandle,THREAD_PRIORITY_NORMAL);

Reply

Marsh Posté le 06-06-2001 à 18:51:57    

bruce a écrit a écrit :

Hu ?  :??:




 
prend l'aide de Builder à "TThread" je crois que c'est ce qu'il y aura de plus facile pour commencer...
sinon dans les exemples fournis il doit bien y en avoir un qui fait ça...


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:54:53    

Franchement moi j'utiliserais l'API c'est bien plus simple, je viens de jetter un oeil dans c++ builder  :D  
Attention, bientôt il va te faire utiliser Delphi, je connais bien antp  :hap:  :hap:

Reply

Marsh Posté le 06-06-2001 à 18:58:52    

robripper a écrit a écrit :

Franchement moi j'utiliserais l'API c'est bien plus simple, je viens de jetter un oeil dans c++ builder  :D  
Attention, bientôt il va te faire utiliser Delphi, je connais bien antp  :hap:  :hap:




 
ok pour l'API
avec Delphi le .exe serait moins gros :P


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-06-2001 à 18:59:25    

Tu crées juste un thread, tu lui passes ta fonction en param (cell qui va faire tout le travail)... etc
 
En plus ici t'es pas obligé de section critique donc ...
 
DWORD WINAPI ma_fonction(LPVOID)
{
 
       // ... rippage, normalisation, etc etc ...  :sol:  
 
      return 0;
}

Reply

Marsh Posté le 06-06-2001 à 19:02:04    

Honettement je suis un peu paumé, je vois pas trop ou vous voulez en venir (il faut dire que jes thread et moi... :)).


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le 06-06-2001 à 19:13:48    

oui... je vois pas pourquoi vous lui parlez de threads ...
 
comme je te disais, le probleme vient de ReadFile qui est bloquant tant que rien n'est ecrit dans ton stdout... c'est a dire que si tu as un prog qui va ecrire un truc, attendre 5 secondes, ecrire un autre truc, readfile va bloquer ton appli pendant les 5 secondes ou le prog. n'ecrit rien dans le stdout...
 
 
il faut que tu remplaces le ReadFile bloquant:

Citation :


  if(ReadFile(hReadPipe, &dest, sizeof(dest), &BytesRead, NULL)) {
   [...]
  }


 
par un test pour savoir si il y a qqchose a lire et ensuite, si il y a qqchose, le lire (qui ne sera pas bloquant puisque tu vas lire exactement ce qu'il y a):

Citation :


  PeekNamedPipe (hOutPipeRead, nil, 0, @dwRead, @dwLeft, nil);  
 
  // has anything been read?  
  if (dwLeft <> 0) then  
  begin  
    ReadFile(hOutPipeRead, Buffer, dwLeft, dwRead, nil);  
    [...]
  end;


---------------
www.alliancefrancophone.org ... Home is where the heart is
Reply

Marsh Posté le 07-06-2001 à 16:21:24    

un cht'i up car bon... je suis tj bloqué...


---------------
A+++ Bruce - http://www.bheller.com
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed