Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write binary data into stdout in Delphi?

How do I write to stdout from Delphi console application?

Here's what I have tried. I have rigged this simple test app according to infos I could find, to read a file from disk and output it to console stdout:

program ConsoleOut;
{$APPTYPE CONSOLE}
uses
  Classes, Windows, SysUtils;

var
  S: TMemoryStream;
  OutputStream: THandleStream;
  ss: string;
  Buffer: PByte;
  i: Integer;
begin
  S := TMemoryStream.Create;
  S.LoadFromFile('1.jpg');
  S.Seek(0, soFromBeginning);

  //Am I right that from now on writing to OutputStream will write to stdout?
  OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));

  GetMem(Buffer, S.Size);
    S.ReadBuffer(Buffer^, S.Size);
    i := OutputStream.Write(Buffer^, S.Size); //i = 0 here for some reason
  FreeMem(Buffer, S.Size);

  Writeln(i, ' byte written to output');
  Readln(ss); //Don't exit app to read previous line
  S.Free;
end.

But for some reason it fails. Could you please direct me into proper way of writing to stdout?

like image 621
Kromster Avatar asked Mar 21 '13 07:03

Kromster


1 Answers

Your approach is sound. However, if stdout is attached to a console then your code fails. A call to GetLastError following the stream write reveals the error code ERROR_NOT_ENOUGH_MEMORY:

Not enough storage is available to process this command.

If you redirect stdout to a file then your code will work fine. And surely you don't really want to spew binary data to the console. That's just going to put unreadable content on the console and make the computer beep annoyingly!

If you must output to the console then you'll need to find out how big the console device buffer is and write to it in appropriately sized chunks. I must confess that I'm not sure how you go about doing that. You could use trial and error, but that doesn't appeal to me. Presumably there is a way to query the console to find out the information.

Looking at the documentation for WriteConsole, it seems that 64K is the upper limit. And indeed if I write spaces to your handle stream then I can write nearly 64K in one go. However, if I write raw JPEG binary data, then it gives out earlier. So I think that's part of the problem too – don't dump a JPEG onto the console.

One other comment. Since you read the contents of the file into a memory stream, there's no need to allocate an intermediate buffer. You can write S.Memory^ directly.

like image 156
David Heffernan Avatar answered Oct 13 '22 07:10

David Heffernan