Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: help with Delphi code (Read 2195 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

help with Delphi code

hello.

trying to cover this topic, i decided to use directly pipes in delphi to support unicode files (+paths) in my program.
i am turning to you for help cause i have no more ideas what i can do wrong.
the code i paste below input file 'a.flac' to encoder through pipe, and receive the results through another one. function seems to work, but weirdly stops receiving data after about 98% done. the piece i save on the disc matches with respondent reference WAV file, except it is only a 98% piece. notice: whole flac file IS passed to encoder as i can see in in task manager.

('a.flac' -> within debugging, oryginally file is passed as parameter 'Param')

(i am sure its not text/binary mode issue cause 98% could not be encoded if it was, and, there are single \x0A characters in received output)

//edit3: if you think you can help, here is the link to the packege with the code and everything needed to test it.

Code: [Select]
function Run_EN(App:Widestring; Param:Widestring) : string;

var

             SA : TSecurityAttributes;
             SI : TStartupInfo;
             PI : TProcessInformation;
StdOutPipeRead,
StdOutPipeWrite,
StdInPipeRead,
StdInPipeWrite,
StdErrPipeRead,
StdErrPipeWrite : THandle;
    WasOKwrite,
     WasOKread,
      ProcessOK : Boolean;
         Buffer : array[0..65535] of char; //or bytes, whatever
     BytesRead,
  BytesWritten,
           Code : Cardinal;
              F : TTntFileStream;
              M : TMemoryStream;
            Read : longword;
  
begin

//SAME1
{SA.nLength:=sizeof(SA);
SA.lpSecurityDescriptor:=nil;
SA.bInheritHandle:=TRUE;

if (CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 65536)and CreatePipe(StdInPipeRead, StdInPipeWrite, @SA, 65536) and CreatePipe(StdErrPipeRead, StdErrPipeWrite, @SA, 65536)) then
   begin
   ZeroMemory(@SI, sizeof(SI));
   with SI do
     begin
     cb := sizeof(SI);
     dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     wShowWindow := SW_HIDE;
     hStdInput := StdInPipeRead;
     hStdOutput := StdOutPipeWrite;
     hStdError := StdErrPipeWrite;
     end;}
//\SAME1


//SAME_2: just longer
if (CreatePipe(StdOutPipeRead, StdOutPipeWrite, nil, 65536)and CreatePipe(StdInPipeRead, StdInPipeWrite, nil, 65536) and CreatePipe(StdErrPipeRead, StdErrPipeWrite, nil, 65536)) then
   begin

   DuplicateHandle(GetCurrentProcess(), StdOutPipeWrite,GetCurrentProcess(), @StdOutPipeWriteDup, 0, True,DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS);
   DuplicateHandle(GetCurrentProcess(), StdInPipeRead,GetCurrentProcess(), @StdInPipeReadDup, 0, True,DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS);
   DuplicateHandle(GetCurrentProcess(), StdErrPipeWrite,GetCurrentProcess(), @StdErrPipeWriteDup, 0, True,DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS);

   ZeroMemory(@SI, sizeof(SI));
   with SI do
     begin
     cb := sizeof(SI);
     dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     wShowWindow := SW_HIDE;
     hStdInput := StdInPipeReadDup;
     hStdOutput := StdOutPipeWriteDup;
     hStdError := StdErrPipeWriteDup;
     end;
//\SAME_2


   ProcessOK:=CreateProcessW(nil,pwidechar('flac.exe -d -o - --totally-silent -'), nil, nil, TRUE, 0, nil, pwidechar(FWorkDir), SI, PI);

  

//SAME_1
{   CloseHandle(StdInPipeRead);StdInPipeRead:=0;
   CloseHandle(StdOutPipeWrite);StdOutPipeWrite:=0;
   CloseHandle(StdErrPipeWrite);StdErrPipeWrite:=0;}
//\SAME_1

//SAME_2
   CloseHandle(StdInPipeReadDup);StdInPipeReadDup:=0;
   CloseHandle(StdOutPipeWriteDup);StdOutPipeWriteDup:=0;
   CloseHandle(StdErrPipeWriteDup);StdErrPipeWriteDup:=0;
//\SAME_2

   F:=TFileStream.Create('a.flac', fmOpenRead or fmShareDenyWrite);
   M:=TMemoryStream.Create;

     WasOKwrite:=true;
   bytesWritten:=1;
   BytesToWrite := F.Read(FileBuffer, 65536);

   if ProcessOK then
      while (BytesToWrite>0)and(WasOKwrite)and(bytesWritten>0) do
        begin
        WasOKwrite:=WriteFile(StdInPipeWrite, FileBuffer, BytesToWrite, bytesWritten, nil);
        while WaitForSingleObject(PI.hProcess, 20)=WAIT_OBJECT_0 do Application.ProcessMessages;
          repeat
          if PeekNamedPipe(StdOutPipeRead,nil,0,nil,@BytesToRead,nil) and (BytesToRead>0) then
//Peek must be or hangs
//after ~98% it says '0' bytes left
             begin
             setlength(PipeBuffer,BytesToRead);
             WasOKread:=ReadFile(StdOutPipeRead, PipeBuffer[0], BytesToRead, bytesRead, nil);
             Written:=M.Write(PipeBuffer[0], bytesRead);
             end
          else Break;
          until not WasOKread or (BytesRead = 0);
          
          //there is no error anyway
  {        repeat
          if PeekNamedPipe(StdErrPipeRead,nil,0,nil,@BytesToRead,nil) and (BytesToRead>0) then
             WasOKread:=ReadFile(StdErrPipeRead, Buffer, BytesToRead, bytesRead, nil)
          else Break;
          until not WasOKread or (BytesRead = 0);}

        BytesToWrite := F.Read(FileBuffer, 65536);
        end;

//save result to compare externally
   M.SaveToFile('a.wav');

   M.Free;
   F.Free;
   SetLength(PipeBuffer,0);
   CloseHandle(PI.hThread);
   CloseHandle(PI.hProcess);
   TerminateProcess(PI.hProcess, Code);
   CloseHandle(StdOutPipeRead);
   CloseHandle(StdErrPipeRead);
   CloseHandle(StdInPipeWrite);
   end;
end;


thing that makes me wondering:

in a simplier version of this function, where i only capture the output and pass input to encoder normally
'flac.exe -d -c --totally-silent a.flac'
my 'reading' code looks like this (the simplier only-reading version works fine !!!):

Code: [Select]
   if ProcessOK then
      repeat
         WasOKread:=ReadFile(StdOutPipeRead, Buffer, 65536, BytesRead, nil);
         M.Write(Buffer, bytesRead);
      until not WasOKread or (BytesRead = 0);


no peek needed, and the more, when i only use it

Code: [Select]
   if ProcessOK then
      repeat
      if PeekNamedPipe(StdOutPipeRead,nil,0,nil,@BytesRead,nil) and (BytesRead>0) then
         begin
         WasOKread:=ReadFile(StdOutPipeRead, Buffer, 65536, BytesRead, nil);
         M.Write(Buffer, bytesRead);
         end
      else break;
      until not WasOKread or (BytesRead = 0);


file is NOT read. from all i know, this function with these parameters ONLY checks if something is waiting in a pipe, so teoretically it is even more proper. but this is just what i found trying to make working the 'full' version above.

i hope you are smarter than me  and will tell me whats wrong...!

//edit:
i noticed ~98% on two (all i tried, big~22MB and small~0,5MB one) FLAC files. when i tried same thing with lame and 52KB MP3 file, i got only 53KB output, instead of 517KB. i also noticed, that small changes in code, like now
      
Code: [Select]
while WaitForSingleObject(PI.hProcess, 20)=WAIT_OBJECT_0 do Application.ProcessMessages;

becomes->
      
Code: [Select]
while WaitForSingleObject(PI.hProcess, 10)=WAIT_OBJECT_0 do Application.ProcessMessages;

i got less output, so if before i got from 437KB FLAC file always 448KB output, now i have 432KB. but no matter how much time i give, its never more than that previous 448KB.

hmm...am i dumb or something ?

//edit2:
one more thing : PeekNamedPipe does not return any error.