问题
I try several samples in the internet and none of them work - the scripts are not executed- (maybe because are for pre Delphi 2009 unicode?).
I need to run some python scripts and pass arguments to them, like:
python "..\Plugins\RunPlugin.py" -a login -u Test -p test
And capture the output to a string & the errors to other.
This is what I have now:
procedure RunDosInMemo(DosApp:String; var OutData: String);
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of Char;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
begin
OutData := '';
with SA do begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES or CREATE_UNICODE_ENVIRONMENT;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
WorkDir := 'C:\';
Handle := CreateProcess(nil, PChar(DosApp),
nil, nil, True, 0, nil,
PChar(WorkDir), SI, PI);
CloseHandle(StdOutPipeWrite);
if Handle then
begin
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
OutData := OutData + String(Buffer);
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end else begin
raise Exception.Create('Failed to load python plugin');
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
回答1:
I'm not certain the WaitForSingleObject is the way to go... I think its better to loop with GetExitCodeProcess(pi.hProcess,iExitCode) until iExitCode <> STILL_ACTIVE and then check for data on each pass through the loop.
The code as written does not operate under Delphi 2007 either, so its not a Delphi 2009 unicode issue.
Changing your inner loop to the following works:
if Handle then
begin
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
for ix := 0 to BytesRead-1 do
begin
OutData := OutData + AnsiChar(Buffer[ix]);
end;
GetExitCodeProcess(pi.hProcess,iExit);
until (iExit <> STILL_ACTIVE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
I made the following corrections/additions to the local variables:
Buffer: array[0..255] of byte;
iExit : Cardinal;
IX : integer;
I also moved the CloseHandle(StdOutPipeWrite) just before the close of the StdOutPipeRead.
回答2:
Create_Unicode_Environment
is a process creation flag, meant for use in the dwCreationFlags
parameter of CreateFile
. It is not a flag for use in the TStartupInfo
record. API functions are liable to fail if you give them flag values they don't understand, and they're liable to do strange things if you give them flag values that mean something other than what you expected.
You declare a buffer of 256 Char
s; recall that Char
in Delphi 2009 is a 2-byte Unicode type. You then call ReadFile
and tell it that the buffer is 255 bytes long instead of the real value, 512. When the documentation says that a value is the number of bytes, take that as your cue to use the SizeOf
function.
Since ReadFile
reads bytes, it would be a good idea to declare your buffer array to be an array of byte-sized elements, such as AnsiChar
. That way, when you set Buffer[BytesRead]
, you won't include twice the data you actually read.
The Unicode version of CreateProcess
may modify its command-line argument. You must ensure that the string you pass to that parameter has a reference count of 1. Call UniqueString(DosApp)
before you call CreateProcess
.
When an API function fails, you will of course want to know why. Don't just make up a reason. Use the functions provided, such as Win32Check
and RaiseLastOSError
. At the very least, call GetLastError
, like MSDN tells you to. Don't throw a generic exception type when a more specific one is readily available.
来源:https://stackoverflow.com/questions/841047/how-in-delphi-2009-redirect-console-stin-sterr