Zdravím, můj problém je následující:
Potřebuji nějakým způsobem přesměrovat to, co se zapisuje do konzole pomocí Write(Ln), do souboru (svým způsobem log) ale s tím, že se to bude normálně v té konzoli zobrazovat. Zkrátka se chci napíchnout na StdOut a lít ho do logu aniž bych ho nijak měnil, aneb co je vidět v konzoli aby bylo zapsáno do souboru. Samotné přesměrování do souboru není problém pomocí AssignFile(Output,...), ale pak se (pochopitelně) nic nozobrazí v konzoli.
Zkoušel jsem přesměrovat StdOut na pipe pomocí SetConsoleHandle atd., ale to nefunguje. Takhle to momentálně vypadá:
unit StdOut2File;
interface
implementation
uses
Windows;
type
TThreadParams = record
Terminated: Integer;
ReadPipe: THandle;
WritePipe: THandle;
OldStdOut: THandle;
Event: THandle;
Thread: THandle;
ThreadID: LongWord;
end;
PThreadParams = ^TThreadParams;
var
ThreadParams: TThreadParams;
Function ThrProc(Param: PThreadParams): DWORD; stdcall;
const
BufferSize = 1024;
var
Buffer: Pointer;
BytesRead: LongWord;
BytesWritten: LongWord;
Function Terminated: Boolean;
begin
Result := InterlockedExchange(Param^.Terminated,0) <> 0;
end;
begin
GetMem(Buffer,BufferSize);
try
while not Terminated do
begin
PeekNamedPipe(ThreadParams.ReadPipe,nil,BufferSize,nil,@BytesRead,nil);
If BytesRead > 0 then
begin
ReadFile(ThreadParams.ReadPipe,Buffer^,BufferSize,BytesRead,nil);
WriteFile(ThreadParams.OldStdOut,Buffer^,BytesRead,BytesWritten,nil);
//... write buffer to a file
end
else WaitForSingleObject(Param^.Event,100);
end;
finally
FreeMem(Buffer,BufferSize);
end;
Result := 0;
end;
procedure Initialize;
begin
InterlockedExchange(ThreadParams.Terminated,0);
CreatePipe(ThreadParams.ReadPipe,ThreadParams.WritePipe,nil,0);
ThreadParams.OldStdOut := GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE,ThreadParams.WritePipe);
ThreadParams.Event := CreateEvent(nil,False,False,nil);
ThreadParams.Thread := CreateThread(nil,0,@ThrProc,@ThreadParams,0,ThreadParams.ThreadID);
end;
procedure Finalize;
begin
InterlockedExchange(ThreadParams.Terminated,1);
SetEvent(ThreadParams.Event);
WaitForSingleObject(ThreadParams.Thread,INFINITE);
SetStdHandle(STD_OUTPUT_HANDLE,ThreadParams.OldStdOut);
CloseHandle(ThreadParams.ReadPipe);
CloseHandle(ThreadParams.WritePipe);
CloseHandle(ThreadParams.Thread);
CloseHandle(ThreadParams.Event);
end;
initialization
Initialize;
finalization
Finalize;
end.
var
TestStr: String = 'Hello World!' + sLineBreak;
OutBytes: LongWord;
begin
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),PChar(TestStr)^,Length(TestStr) * SizeOf(Char),OutBytes,nil); // funguje, v pipe je text
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),PChar(TestStr),Length(TestStr) * SizeOf(Char),OutBytes,nil); // nefunguje, pipe je prázdná (zřejmě kvůli jinému handle, očekává console screen buffer)
WriteLn(TestStr); // nefunguje, pipe je prázdná
ReadLn;
end.
Poradí mi někdo kde dělám nesmysly, případně jak to udělat jinak (a ideálně funkčně ;D )?
Je to v Delphi 7 Personal.
Předem díky.