06. september 2000 - 00:18
#5
Jeg har \"oversat\" det ex jeg henvendte til tidligere (fra C++ til Delphi), og lavet det til et unit (bevaret alle kommentarerne):
// START HER FRA
unit ReDir;
interface
uses windows;
const BUFSIZE = 4096;
var hSaveStdin, hSaveStdout, hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdinWrDup,
hChildStdoutWr, hChildStdoutRdDup, hInputFile : THandle;
function CreateChildProcess : Boolean;
procedure WriteToPipe;
procedure ReadFromPipe;
procedure ErrorExit(lpszMessage : String);
procedure DoSomeRedir(AppFile, Params, InputFile : String);
implementation
var fAppFile, fParams, fInputFile : String;
function CreateChildProcess : Boolean;
var piProcInfo : TPROCESSINFORMATION;
siStartInfo : TSTARTUPINFO;
begin
// Set up members of the PROCESS_INFORMATION structure.
FillChar(piProcInfo, sizeof(TPROCESSINFORMATION), 0);
// Set up members of the STARTUPINFO structure.
FillChar(siStartInfo, sizeof(TSTARTUPINFO), 0);
siStartInfo.cb := sizeof(TSTARTUPINFO);
// Create the child process.
Result := CreateProcess(nil,
PChar(fAppFile + \' \' + fParams), // command line
nil, // process security attributes
nil, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
nil, // use parent\'s environment
nil, // use parent\'s current directory
siStartInfo, // STARTUPINFO pointer
piProcInfo); // receives PROCESS_INFORMATION
end;
procedure WriteToPipe;
var
dwRead, dwWritten : DWORD;
chBuf : packed Array[1..BUFSIZE] of Char;
begin
// Read from a file and write its contents to a pipe.
if fInputFile <> \'\' then
begin
while true do
begin
FillChar(chBuf, BUFSIZE, 0);
if (not ReadFile(hInputFile, chBuf, BUFSIZE, dwRead, nil)) or (dwRead = 0) then break;
if not WriteFile(hChildStdinWrDup, chBuf, dwRead, dwWritten, nil) then break;
end;
end;
// Close the pipe handle so the child process stops reading.
if not CloseHandle(hChildStdinWrDup) then ErrorExit(\'Close pipe failed\');
end;
procedure ReadFromPipe;
var
dwRead, dwWritten : DWORD;
chBuf : packed Array[1..BUFSIZE] of Char;
hStdout : THandle;
begin
hStdout := GetStdHandle(STD_OUTPUT_HANDLE);
// Close the write end of the pipe before reading from the
// read end of the pipe.
if not CloseHandle(hChildStdoutWr) then ErrorExit(\'Closing handle failed\');
// Read output from the child process, and write to parent\'s STDOUT.
while true do
begin
FillChar(chBuf, BUFSIZE, 0);
if (not ReadFile(hChildStdoutRdDup, chBuf, BUFSIZE, dwRead, nil)) or (dwRead = 0) then break;
if not WriteFile(hSaveStdout, chBuf, dwRead, dwWritten, nil) then break;
MessageBox(0, PChar(String(chBuf)), \'Txt\', MB_OK);
end;
end;
procedure ErrorExit(lpszMessage : String);
begin
MessageBox(0, PChar(lpszMessage), \'Fejl!\', MB_OK);
// fprintf(stderr, \"%s\\n\", lpszMessage);
ExitProcess(0);
end;
procedure DoSomeRedir(AppFile, Params, InputFile : String);
var
saAttr : TSECURITYATTRIBUTES;
fSuccess : Boolean;
begin
fAppFile := AppFile;
fParams := Params;
fInputFile := InputFile;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength := sizeof(TSECURITYATTRIBUTES);
saAttr.bInheritHandle := TRUE;
saAttr.lpSecurityDescriptor := nil;
// The steps for redirecting child process\'s STDOUT:
// 1. Save current STDOUT, to be restored later.
// 2. Create anonymous pipe to be STDOUT for child process.
// 3. Set STDOUT of the parent process to be write handle to
// the pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the read handle and
// close the inheritable read handle.
// Save the handle to the current STDOUT.
hSaveStdout := GetStdHandle(STD_OUTPUT_HANDLE);
// Create a pipe for the child process\'s STDOUT.
if not CreatePipe(hChildStdoutRd, hChildStdoutWr, @saAttr, 0) then
ErrorExit(\'Stdout pipe creation failed\');
// Set a write handle to the pipe to be STDOUT.
if not SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr) then
ErrorExit(\'Redirecting STDOUT failed\');
// Create noninheritable read handle and close the inheritable read
// handle.
fSuccess := DuplicateHandle(GetCurrentProcess, hChildStdoutRd,
GetCurrentProcess, @hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if not fSuccess then ErrorExit(\'DuplicateHandle failed\');
CloseHandle(hChildStdoutRd);
// The steps for redirecting child process\'s STDIN:
// 1. Save current STDIN, to be restored later.
// 2. Create anonymous pipe to be STDIN for child process.
// 3. Set STDIN of the parent to be the read handle to the
// pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the write handle,
// and close the inheritable write handle.
// Save the handle to the current STDIN.
hSaveStdin := GetStdHandle(STD_INPUT_HANDLE);
// Create a pipe for the child process\'s STDIN.
if not CreatePipe(hChildStdinRd, hChildStdinWr, @saAttr, 0) then ErrorExit(\'Stdin pipe creation failed\');
// Set a read handle to the pipe to be STDIN.
if not SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd) then ErrorExit(\'Redirecting Stdin failed\');
// Duplicate the write handle to the pipe so it is not inherited.
fSuccess := DuplicateHandle(GetCurrentProcess, hChildStdinWr,
GetCurrentProcess, @hChildStdinWrDup, 0,
FALSE, // not inherited
DUPLICATE_SAME_ACCESS);
if not fSuccess then ErrorExit(\'DuplicateHandle failed\');
CloseHandle(hChildStdinWr);
// Now create the child process.
if not CreateChildProcess then ErrorExit(\'Create process failed\');
// After process creation, restore the saved STDIN and STDOUT.
if not SetStdHandle(STD_INPUT_HANDLE, hSaveStdin) then ErrorExit(\'Re-redirecting Stdin failed\');
if not SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout) then ErrorExit(\'Re-redirecting Stdout failed\');
// Get a handle to the parent\'s input file.
if fInputFile <> \'\' then
hInputFile := CreateFile(PChar(fInputFile), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0)
else
hInputFile := hSaveStdin;
if hInputFile = INVALID_HANDLE_VALUE then ErrorExit(\'no input file\');
// Write to pipe that is the standard input for a child process.
WriteToPipe;
// Read from pipe that is the standard output for child process.
ReadFromPipe;
end;
end.
// SLUT HER
Eksempel på at kalde redir-unittet:
//DoSomeRedir(programfil, parametre, inputfil);
// - inputfil = fil hvis indhold bliver kopieret til stdin for programfil (tom streng = intet)
AllocConsole; // Opret stdin og stdout for GUI app
DoSomeRedir(\'attrib.exe\', \'/?\', \'\');
FreeConsole;
Viser en dialog-boks med de parametre attrib.exe (et DOS-program) tager
I ReadFromPipe er indsat et kald til MessageBox, så man kan se hvad stdout byder på - kan sagtens kopieres over i en string som så fx returneres af DoSomeRedir - det var i hvert fald en ide...
Michael