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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With