所有的程序都有标准输入,标准输出,标准错误这三个管道存在, 所以我们想得到控制台程序的输出,可以通过重定向这些管道来实现.
首先, 我们要建立一个管道作为控制台程序的标准输出管道, 因为这个管道要转给控制台程序使用, 所以它应该是可以被控制台程序继承的句柄.
ZeroMemory(@mSa, SizeOf(mSa));
mSa.nLength := SizeOf(mSa);
mSa.bInheritHandle := True; //设定为可以为子进程继承的句柄
mSa.lpSecurityDescriptor := nil;

if not CreatePipe(mOutRd, mOutWr, @mSa, 0) then raise Exception.Create('建立管道出错');
第二步, 复制读管道的句柄, 因为读管道的句柄在建立时是一个可继承句柄, 它可能会被子进程使用, 那样会造成信息的丢失与父进程的堵塞, 所以我们要复制成一个不可以继承句柄, 并且它实际上在子进程中是没有用的, 所以我们在复制成功后要关闭它.
if not DuplicateHandle(GetCurrentProcess, mOutRd, GetCurrentProcess,
@mOutRdDup, 0, False, DUPLICATE_SAME_ACCESS) then
raise Exception.Create('复制读句柄出错');

CloseHandle(mOutRd);
第三步, 我们要建立控制台子进程了
ZeroMemory(@mStartupInfo, SizeOf(mStartupInfo));
mStartupInfo.cb := SizeOf(mStartupInfo);
mStartupInfo.dwFlags := mStartupInfo.dwFlags or STARTF_USESTDHANDLES; //将标准输出重定向
mStartupInfo.hStdOutput := mOutWr;
mStartupInfo.hStdError := mOutWr;
ZeroMemory(@mProcess, SizeOf(mProcess));

if not CreateProcess(nil, cmdLine,nil, nil, True, 0, nil, WorkDir, mStartupInfo,mProcess) then
raise Exception.Create('启动程序出错');

CloseHandle(mProcess.hProcess);
CloseHandle(mProcess.hThread);
第四步, 关闭写句柄, 要不然当子进程关闭了自己后, 会因为写句柄还被父进程所打开, 而使下面的ReadFile无法得知管道已结束, 从而堵塞.
if not CloseHandle(mOutWr) then
raise Exception.Create('标准输出句柄关闭出错');

while ReadFile(mOutRdDup, mBuff, 256, mRealRead, nil) do begin
if mRealRead = 0 then Break;
//作点自己爱作的事情吧
end;
完整的代码如下:
var
mRealRead: DWORD;
mOutRd, mOutWr, mOutRdDup: THandle;
mSa: TSecurityAttributes;
mProcess: TProcessInformation;
mStartupInfo: TStartupInfo;
mBuff: array[0..255] of Char;
begin
ZeroMemory(@mSa, SizeOf(mSa));
mSa.nLength := SizeOf(mSa);
mSa.bInheritHandle := True;
mSa.lpSecurityDescriptor := nil;

if not CreatePipe(mOutRd, mOutWr, @mSa, 0) then raise Exception.Create('建立管道出错');

if not DuplicateHandle(GetCurrentProcess, mOutRd, GetCurrentProcess,
@mOutRdDup, 0, False, DUPLICATE_SAME_ACCESS) then
raise Exception.Create('复制读句柄出错');

CloseHandle(mOutRd);
ZeroMemory(@mStartupInfo, SizeOf(mStartupInfo));
mStartupInfo.cb := SizeOf(mStartupInfo);
mStartupInfo.dwFlags := mStartupInfo.dwFlags or STARTF_USESTDHANDLES;
mStartupInfo.hStdOutput := mOutWr;
mStartupInfo.hStdError := mOutWr;
mStartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
ZeroMemory(@mProcess, SizeOf(mProcess));


if not CreateProcess(nil, cmdLine,nil, nil, True, 0, nil, WorkDir, mStartupInfo,mProcess) then raise Exception.Create('启动程序出错');

CloseHandle(mProcess.hProcess);
CloseHandle(mProcess.hThread);

if not CloseHandle(mOutWr) then
raise Exception.Create('标准输出句柄关闭出错');

while ReadFile(mOutRdDup, mBuff, 256, mRealRead, nil) do begin
if mRealRead = 0 then Break;
mmo1.Lines.Add(mBuff);
Application.ProcessMessages;
end;
首先, 我们要建立一个管道作为控制台程序的标准输出管道, 因为这个管道要转给控制台程序使用, 所以它应该是可以被控制台程序继承的句柄.
ZeroMemory(@mSa, SizeOf(mSa));
mSa.nLength := SizeOf(mSa);
mSa.bInheritHandle := True; //设定为可以为子进程继承的句柄
mSa.lpSecurityDescriptor := nil;
if not CreatePipe(mOutRd, mOutWr, @mSa, 0) then raise Exception.Create('建立管道出错');第二步, 复制读管道的句柄, 因为读管道的句柄在建立时是一个可继承句柄, 它可能会被子进程使用, 那样会造成信息的丢失与父进程的堵塞, 所以我们要复制成一个不可以继承句柄, 并且它实际上在子进程中是没有用的, 所以我们在复制成功后要关闭它.
if not DuplicateHandle(GetCurrentProcess, mOutRd, GetCurrentProcess,
@mOutRdDup, 0, False, DUPLICATE_SAME_ACCESS) then
raise Exception.Create('复制读句柄出错');
CloseHandle(mOutRd);第三步, 我们要建立控制台子进程了
ZeroMemory(@mStartupInfo, SizeOf(mStartupInfo));
mStartupInfo.cb := SizeOf(mStartupInfo);
mStartupInfo.dwFlags := mStartupInfo.dwFlags or STARTF_USESTDHANDLES; //将标准输出重定向
mStartupInfo.hStdOutput := mOutWr;
mStartupInfo.hStdError := mOutWr;
ZeroMemory(@mProcess, SizeOf(mProcess));
if not CreateProcess(nil, cmdLine,nil, nil, True, 0, nil, WorkDir, mStartupInfo,mProcess) then
raise Exception.Create('启动程序出错');
CloseHandle(mProcess.hProcess);
CloseHandle(mProcess.hThread);第四步, 关闭写句柄, 要不然当子进程关闭了自己后, 会因为写句柄还被父进程所打开, 而使下面的ReadFile无法得知管道已结束, 从而堵塞.
if not CloseHandle(mOutWr) then
raise Exception.Create('标准输出句柄关闭出错');
while ReadFile(mOutRdDup, mBuff, 256, mRealRead, nil) do begin
if mRealRead = 0 then Break;
//作点自己爱作的事情吧
end;完整的代码如下:
var
mRealRead: DWORD;
mOutRd, mOutWr, mOutRdDup: THandle;
mSa: TSecurityAttributes;
mProcess: TProcessInformation;
mStartupInfo: TStartupInfo;
mBuff: array[0..255] of Char;
begin
ZeroMemory(@mSa, SizeOf(mSa));
mSa.nLength := SizeOf(mSa);
mSa.bInheritHandle := True;
mSa.lpSecurityDescriptor := nil;
if not CreatePipe(mOutRd, mOutWr, @mSa, 0) then raise Exception.Create('建立管道出错');
if not DuplicateHandle(GetCurrentProcess, mOutRd, GetCurrentProcess,
@mOutRdDup, 0, False, DUPLICATE_SAME_ACCESS) then
raise Exception.Create('复制读句柄出错');
CloseHandle(mOutRd);
ZeroMemory(@mStartupInfo, SizeOf(mStartupInfo));
mStartupInfo.cb := SizeOf(mStartupInfo);
mStartupInfo.dwFlags := mStartupInfo.dwFlags or STARTF_USESTDHANDLES;
mStartupInfo.hStdOutput := mOutWr;
mStartupInfo.hStdError := mOutWr;
mStartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
ZeroMemory(@mProcess, SizeOf(mProcess));

if not CreateProcess(nil, cmdLine,nil, nil, True, 0, nil, WorkDir, mStartupInfo,mProcess) then raise Exception.Create('启动程序出错');
CloseHandle(mProcess.hProcess);
CloseHandle(mProcess.hThread);
if not CloseHandle(mOutWr) then
raise Exception.Create('标准输出句柄关闭出错');
while ReadFile(mOutRdDup, mBuff, 256, mRealRead, nil) do begin
if mRealRead = 0 then Break;
mmo1.Lines.Add(mBuff);
Application.ProcessMessages;
end;

被折叠的 条评论
为什么被折叠?



