命令行管道重定向问题(双向),请tseug进来看看 (200分)

  • 主题发起人 主题发起人 skyweb
  • 开始时间 开始时间
S

skyweb

Unregistered / Unconfirmed
GUEST, unregistred user!
我做的一个函数用于执行一个命令行程序,向该程序的标准输入写数据,然后从该程序<br>的标准输出中读出处理结果。这个函数在Windows NT/XP下调试通过,可以正常运行,<br>但在Win9x(我用的是WinMe)下却不能工作,分析的结果大致是该命令行程序以为其标<br>准输入尚未结束,所以不输出也不结束,头痛~~~。<br><br>简言之,我需要一个能在Win9x/Me下工作的双管道重定向命令行输入输出的例子。<br><br>各位高手看看有什么好建议?<br><br>procedure ExecInterpreter(const Interpreter: string;<br>&nbsp; AppInput, AppOutput: TStrings);<br>var<br>&nbsp; StartupInfo:TStartupInfo;<br>&nbsp; ProcessInfo:TProcessInformation;<br>&nbsp; SecurityAttributes: TSecurityAttributes;<br>&nbsp; // MyOutput和ChildInput分别为输出管道(本进程送往被调进程)的写入和读出端<br>&nbsp; MyOutput,<br>&nbsp; ChildInput,<br>&nbsp; // MyOutput和ChildInput分别为输入管道(被调进程送往本进程)的写入和读出端<br>&nbsp; ChildOutput,<br>&nbsp; MyInput,<br>&nbsp; TempHandle: THandle;<br>&nbsp; Buffer: array[0..$100]of char;<br>&nbsp; Bytes,ExitCode: Cardinal;<br>&nbsp; Stream: TStream;<br>&nbsp; s: string;<br>begin<br>&nbsp; FillChar(StartupInfo,SizeOf(StartupInfo), 0);<br>&nbsp; FillChar(SecurityAttributes, SizeOf(SecurityAttributes), 0);<br>&nbsp; with SecurityAttributes do<br>&nbsp; begin<br>&nbsp; &nbsp; nLength:= Sizeof(SecurityAttributes);<br>&nbsp; &nbsp; bInheritHandle:= true<br>&nbsp; end;<br><br>&nbsp; // 建立输入管道(从被调进程送往本进程)<br>&nbsp; if not CreatePipe(MyInput, ChildOutput, @SecurityAttributes, $10000) then<br>&nbsp; &nbsp; RaiseLastWin32Error;<br>&nbsp; // 建立输出管道(从本进程送往被调进程)<br>&nbsp; if not CreatePipe(ChildInput, MyOutput, @SecurityAttributes, 0) then<br>&nbsp; &nbsp; RaiseLastWin32Error;<br>&nbsp; with StartupInfo do<br>&nbsp; begin<br>&nbsp; &nbsp; cb:= SizeOf(StartupInfo);<br>&nbsp; &nbsp; dwFlags:= STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;<br>&nbsp; &nbsp; wShowWindow:= SW_HIDE;<br>&nbsp; &nbsp; hStdOutput:= ChildOutput;<br>&nbsp; &nbsp; hStdInput:= ChildInput;<br>&nbsp; &nbsp; hStdError:= ChildOutput;<br>&nbsp; end;<br><br>&nbsp; if not CreateProcess(nil, PChar(Interpreter),<br>&nbsp; &nbsp; &nbsp;nil, nil,<br>&nbsp; &nbsp; &nbsp;true,<br>&nbsp; &nbsp; &nbsp;CREATE_NO_WINDOW,<br>&nbsp; &nbsp; &nbsp;nil,<br>&nbsp; &nbsp; &nbsp;nil,<br>&nbsp; &nbsp; &nbsp;StartupInfo,<br>&nbsp; &nbsp; &nbsp;ProcessInfo) then<br>&nbsp; &nbsp;RaiseLastWin32Error;<br><br>&nbsp; CloseHandle(ChildOutput);<br>&nbsp; CloseHandle(ChildInput);<br><br>&nbsp; // 输出数据到子进程,然后关闭输出管道<br>&nbsp; s:=AppInput.Text;<br>&nbsp; WriteFile(MyOutput, s[1], length(s), Bytes, nil);<br>&nbsp; CloseHandle(MyOutput);<br><br>&nbsp; Stream:=TMemoryStream.Create;<br>&nbsp; try<br>&nbsp; &nbsp; repeat<br>&nbsp; &nbsp; &nbsp; GetExitCodeProcess(ProcessInfo.hProcess,ExitCode);<br>&nbsp; &nbsp; &nbsp; if not PeekNamedPipe(MyInput,nil,0,nil,@Bytes,nil) then<br>&nbsp; &nbsp; &nbsp; &nbsp; RaiseLastWin32Error;<br>&nbsp; &nbsp; &nbsp; Application.ProcessMessages;<br>&nbsp; &nbsp; &nbsp; if Bytes&gt;0 then<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; if not ReadFile(MyInput, Buffer, SizeOf(Buffer), Bytes, nil) then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RaiseLastWin32Error;<br>&nbsp; &nbsp; &nbsp; &nbsp; Stream.WriteBuffer(Buffer,Bytes);<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; until (Bytes=0) and (ExitCode&lt;&gt;STILL_ACTIVE);<br><br>&nbsp; &nbsp; // 将读入的数据装入输出文本列表<br>&nbsp; &nbsp; Stream.Position:=0;<br>&nbsp; &nbsp; AppOutput.LoadFromStream(Stream);<br>&nbsp; finally<br>&nbsp; &nbsp; Stream.Free;<br>&nbsp; &nbsp; CloseHandle(ProcessInfo.hProcess);<br>&nbsp; &nbsp; CloseHandle(MyInput);<br>&nbsp; end<br>end;<br>
 
在建立子进程后等待一会儿后再向子进程输入也许有帮助
 
[:D]大家闲着也是闲着,无风险的 Make 些 Money 呗!钱拿到手别忘了请客哟!<br>网上挣不错!可惜钱太少,现在好了:),反正闲着也是闲着, 找了一个不要身份证,不要会 <br>员费, 只要有个地址,就能挣到钱的网站, 不用开广告条哦! 申请成了会员……(反正挣 <br>不到钱也不会吃亏^o^) 等了一个月,两个月…… 什么汇款单?连个影子都没有! 不过一 <br>想,无所谓了……反正也没吃亏… ^^ 就当是鬼迷心窍一回吧! 可一直到了3个月…… 突 <br>然……汇款单到了?! 不看不知道,一看吓一跳! 9百多美金?折合人民币不就是7千多了 <br>吗? 半信半疑,到了银行,换回了7千多…… 真像做梦一样……买了一些一直想买的东 <br>东…… 兴奋之余,又开始了我的宣传!宣传越多,挣的越多吗 ^o^ 果然,不到一个月,又 <br>飞来了一张单子! 1千3百多美金…… 真是难以置信! 又过了一个月上涨到了2千4百多美 <br>金…… 如今,不用上班也有钱花了,真是乐哉乐哉! 你不信?那没办法!只可惜这白花花 <br>的银子喽…… 不过,古人云:“宁可信其有,不可信其无”啊…… 反正也不吃亏,就当疯 <br>一回试试看嘛…… 相信我,没错的! ****加入方法*** 很简单的哦***  <br>http://www.MintMail.com/?m=2292875 进入上面网站(复制、粘贴到地址栏) 打开网页, <br>点击右上方 click here 活动图标, 或点击蓝色 FREE Sign-up page 字样也可! 然后, <br>跟着提示,一步一步输入信息就ok了。 值得高兴的是它能识别中文信息,而能100%加入! <br>下面是我为了方便大家的加入详细说明了加入过程中的细节 - First name*: 名字(例:文 <br>杰 ) - Last Name*: 姓 (例:肖 ) - Company Name: 可不填 - Street Address*: 家 <br>庭住址:(一定要详细填写,不然收不到汇款单喽!) 例:上海市 **地方 - City*: 城市 <br>名 (例:ShangHai 英文填写 ) - State*: 可不填 - Zip*: 邮编 ( 填 000-000 ) - <br>Country*: 国家( 选 china ) - Phone*: 电话号码 ( 国家代码 86 + 去掉区位号前0 <br>的电话号码) 例:010-64243365 → 86-10-64243365) - Fax: 可不填 - E-mail*: 电子 <br>信箱(所有的交流都通过信箱传递,所以务必填写正确) - Confirm E-mail*: 再次输入信 <br>箱地址 ***** - Year of birth*: 出生年例:1970、1980 - Gender*: 性别 Male(男), <br>Femaie (女) - Password*: 密码 (6位以上)****** - Confirm Password: 确认密码 <br>(必须与上相同)****** - how do you want to receive commission E-mail- how do <br>you want to receive commissions that you earn? 以什么形式接收礼品? *gift <br>certificates(double$$) 奖品 *cash 现金 如要奖品能收到双倍价格的东西, 但都是一些 <br>英文版的书籍、磁带、光盘 等 对于中国人来说,还是选择现金比较合算些,请选择 <br>cash - do you want to be notified when your referrals sing up? 加入会员成功时通 <br>知你吗?选 yes - MintMail.com 请选择自己的爱好或兴趣 (最多可选10种) - Submit <br>点击它 屏幕上就会出现 thank you 的字样 大家有钱一起赚!!!试试看吧.   想推广的话, <br>把以上这短话完全拷贝,.再将它复制到各网站的留言录, 过几天你的邮箱会多了许多得钱 <br>通知。一个月左右就收到过钱了.爽!!! <br>
 
这个的问题太难了吗?我愿意再加300分!!!
 
....<br>WaitForSingleObject(ProcessInfo.hProcess, INFINITE);<br><br>// 将读入的数据装入输出文本列表<br>&nbsp; &nbsp;
 
to savenight: 这招早就用过了,没效果.<br>我的函数中有两个管道,一个向子进程写(第一动作),一个从子进程读(第二动作),<br>现在的情况是,在win9x系统下子进程的ReadFile函数未返回,所以子进程不会结束,<br>用WaitForSingleObject(ProcessInfo.hProcess, INFINITE);永远等不到.<br><br>另外我上面的程序用GetExitCodeProcess(ProcessInfo.hProcess,ExitCode);做判<br>断,其效果与WaitForSingleObject是一样的,但是至少我还可以在调试窗里知道我的<br>程序还在运作,同时保证处理Windows消息,不致于看上去程序象完全死掉一样.<br><br>
 
在http://www.delphibbs.com/delphibbs/dispq.asp?lid=618422中,tseug的回答应该是你所需要的。
 
to HD_Copy:<br>&nbsp; tseug的例子有两个,一个讲通过管道读取命令行输出,这个我已经做到了;<br>另一个讲用一个文件做命令行的输入,另一个文件接收出输出,但我想要的是<br>通过管道输入/输出.另外我的这个函数在WinXP/NT上是可以实现我的要求的,<br>只是在Win9x/Me下不行而已.<br>&nbsp; 谢谢.
 
to skyweb:<br>&nbsp; &nbsp;我昨天自己试了一下,也没弄明白。我对用管道技术操纵控制台程序研究得并不深,只是以前用<br>&nbsp; &nbsp;C++Builder写了一个UPX的Windows外壳,下面这个帖子中就是我的那段C++代码,我之所以这么关心<br>&nbsp; &nbsp;你这个题目,是因为我对这方面挺感兴趣的<br>&nbsp; &nbsp;下面是那个帖子中xianjun给我发过来的代码,由于工程文件损坏了,打不开,代码又不多,只有<br>&nbsp; &nbsp;两个单元文件,我就都给你贴上来了,希望你早日成功!<br>&nbsp; &nbsp;<br>//--------------------------------------------------------------------------------------<br>unit Main;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp; StdCtrls, uRedirect, ComCtrls;<br><br>type<br>&nbsp; TForm1 = class(TForm)<br>&nbsp; &nbsp; Memo1: TRichEdit;<br>&nbsp; &nbsp; Edit1: TEdit;<br>&nbsp; &nbsp; procedure Edit1KeyPress(Sender: TObject; var Key: Char);<br>&nbsp; &nbsp; procedure FormClose(Sender: TObject; var Action: TCloseAction);<br>&nbsp; &nbsp; procedure FormShow(Sender: TObject);<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; FRedirector: TRedirector;<br>&nbsp; &nbsp; procedure NewData(Sender: TRedirector; Buffer: Pointer; BufferSize:<br>&nbsp; &nbsp; &nbsp; Integer);<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br>&nbsp; end;<br><br>var<br>&nbsp; Form1: TForm1;<br><br>implementation<br><br>{$R *.DFM}<br><br>procedure TForm1.NewData(Sender: TRedirector; Buffer: Pointer;<br>&nbsp; BufferSize: Integer);<br>var<br>&nbsp; Temp: PChar;<br>begin<br>&nbsp; Temp := StrAlloc(BufferSize + 1);<br>&nbsp; try<br>&nbsp; &nbsp; StrLCopy(Temp, Buffer, BufferSize);<br>&nbsp; &nbsp; Temp[BufferSize] := #0;<br>&nbsp; &nbsp; Memo1.Lines.Add(string(Temp));<br>&nbsp; &nbsp; Memo1.Perform(WM_VSCROLL, SB_BOTTOM, 0);<br>&nbsp; finally<br>&nbsp; &nbsp; StrDispose(Temp);<br>&nbsp; end;<br>end;<br><br>procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);<br>var<br>&nbsp; cmd: string;<br>begin<br>&nbsp; if Key = #13 then<br>&nbsp; begin<br>&nbsp; &nbsp; cmd := Edit1.Text;<br>&nbsp; &nbsp; if cmd = 'NEWCMD' then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if FRedirector &lt;&gt; nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; FRedirector.SendText('exit');<br>&nbsp; &nbsp; &nbsp; FreeAndNil(FReDirector);<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if FRedirector = nil then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FRedirector := TRedirector.Create;<br>&nbsp; &nbsp; &nbsp; FRedirector.KillOnDestroy := True;<br>&nbsp; &nbsp; &nbsp; FRedirector.OnData := NewData;<br>&nbsp; &nbsp; &nbsp; FRedirector.CommandLine := 'cmd';<br>&nbsp; &nbsp; &nbsp; FRedirector.Directory := 'C:/';<br>&nbsp; &nbsp; &nbsp; FRedirector.Execute;<br>&nbsp; &nbsp; &nbsp; FRedirector.SendText('请不要使用需要用户介入的DOS命令(如Edit)'#13#10'否则会死得很难看的! &nbsp;--- XJG在此忠告市民'#10#13);<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if UpperCase(cmd) &lt;&gt; 'EXIT' then<br>&nbsp; &nbsp; &nbsp; FRedirector.SendText(cmd + #10#13);<br>&nbsp; &nbsp; Edit1.SelectAll;<br>&nbsp; end;<br>end;<br><br>procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);<br>begin<br>&nbsp; if Assigned(FRedirector) then<br>&nbsp; &nbsp; FRedirector.Free;<br>end;<br><br>procedure TForm1.FormShow(Sender: TObject);<br>var<br>&nbsp; Key: Char;<br>begin<br>&nbsp; Key := #13;<br>&nbsp; Edit1KeyPress(Edit1, Key);<br>&nbsp; Edit1.Text := '请在此输入你要执行的DOS命令';<br>end;<br><br>end.<br><br>//--------------------------------------------------------------------------------------<br>//****************************************************************************<br>//* I have no idea who wrote this unit, if somebody knows drop me a line and *<br>//* I will credit accordingly. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *<br>//* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br>//* Unit was taken from http://www.delphidevelopers.com &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br>//****************************************************************************<br>{***************************************************************<br>&nbsp;*<br>&nbsp;* History: &nbsp; &nbsp; &nbsp;Modified by xjg.<br>&nbsp;* 参见:http://support.microsoft.com/support/kb/articles/Q190/3/51.ASP<br>&nbsp;*<br>&nbsp;****************************************************************}<br><br>unit uRedirect;<br><br>interface<br><br>uses<br>&nbsp; Windows, SysUtils, Classes;<br><br>type<br>&nbsp; TRedirector = class;<br>&nbsp; TPriorityClass = (pcDefault, pcIdle, pcNormal, pcHigh, pcRealtime);<br>&nbsp; TDataEvent = procedure(Sender: TRedirector; buffer: pointer; Size: integer) of<br>&nbsp; &nbsp; object;<br><br>&nbsp; TPipeError = record<br>&nbsp; &nbsp; hRead,<br>&nbsp; &nbsp; &nbsp; hWrite: DWORD;<br>&nbsp; end;<br><br>&nbsp; TRedirector = class<br>&nbsp; private<br>&nbsp; &nbsp; FAvailable: integer;<br>&nbsp; &nbsp; procedure ReadStdOutput;<br>&nbsp; &nbsp; procedure ReadStdError;<br>&nbsp; &nbsp; procedure ProcessTerminated;<br>&nbsp; protected<br>&nbsp; &nbsp; FProcessInfo: TProcessInformation;<br>&nbsp; &nbsp; FExitCode: integer;<br>&nbsp; &nbsp; FExecutable: string;<br>&nbsp; &nbsp; FCommandline: string;<br>&nbsp; &nbsp; FDefaultErrorMode: boolean;<br>&nbsp; &nbsp; FStartSuspended: boolean;<br>&nbsp; &nbsp; FKillOnDestroy: boolean;<br>&nbsp; &nbsp; FDirectory: string;<br>&nbsp; &nbsp; FEnvironment: pointer;<br>&nbsp; &nbsp; FInitialPriority: TPriorityClass;<br>&nbsp; &nbsp; FPipeInput,<br>&nbsp; &nbsp; &nbsp; FPipeOutput,<br>&nbsp; &nbsp; &nbsp; FPipeError: TPipeError;<br>&nbsp; &nbsp; FThread: TThread;<br>&nbsp; &nbsp; FOnData,<br>&nbsp; &nbsp; &nbsp; FOnErrorData: TDataEvent;<br>&nbsp; &nbsp; FOnTerminated: TNotifyEvent;<br>&nbsp; &nbsp; FShowWindow: integer;<br>&nbsp; &nbsp; procedure Error(msg: string);<br>&nbsp; &nbsp; procedure WinError(msg: string);<br>&nbsp; &nbsp; procedure CreatePipes;<br>&nbsp; &nbsp; procedure ClosePipes;<br>&nbsp; &nbsp; function GetRunning: boolean;<br>&nbsp; &nbsp; function GetExitCode: integer;<br>&nbsp; &nbsp; function GetProcessID: integer;<br>&nbsp; &nbsp; function GetThreadID: integer;<br>&nbsp; &nbsp; function GetProcessHandle: integer;<br>&nbsp; &nbsp; procedure SetShowWindow(value: integer);<br>&nbsp; &nbsp; function GetThreadHandle: integer;<br>&nbsp; &nbsp; procedure SetExecutable(value: string);<br>&nbsp; &nbsp; function GetCommandLine: string;<br>&nbsp; &nbsp; procedure SetCommandLine(value: string);<br>&nbsp; &nbsp; procedure SetDefaultErrorMode(value: boolean);<br>&nbsp; &nbsp; procedure SetStartSuspended(value: boolean);<br>&nbsp; &nbsp; procedure SetInitialPriority(value: TPriorityClass);<br>&nbsp; &nbsp; procedure SetDirectory(value: string);<br>&nbsp; &nbsp; procedure SetEnvironment(value: pointer);<br>&nbsp; &nbsp; property ProcessHandle: integer read GetProcessHandle;<br>&nbsp; &nbsp; property ThreadHandle: integer read GetThreadHandle;<br>&nbsp; public<br>&nbsp; &nbsp; destructor Destroy; override;<br>&nbsp; &nbsp; procedure Terminate(dwExitCode: integer);<br>&nbsp; &nbsp; procedure Execute;<br>&nbsp; &nbsp; procedure SendData(Buffer: pointer; BufferSize: integer);<br>&nbsp; &nbsp; procedure SendText(s: string);<br>&nbsp; &nbsp; property Running: boolean read GetRunning;<br>&nbsp; &nbsp; property ExitCode: integer read GetExitCode;<br>&nbsp; &nbsp; property ProcessID: integer read GetProcessID;<br>&nbsp; &nbsp; property ThreadID: integer read GetThreadID;<br>&nbsp; &nbsp; property Environment: pointer read FEnvironment write SetEnvironment;<br>&nbsp; published<br>&nbsp; &nbsp; property KillOnDestroy: boolean read FKillOnDestroy write FKillOnDestroy;<br>&nbsp; &nbsp; property Executable: string read FExecutable write SetExecutable;<br>&nbsp; &nbsp; property CommandLine: string read GetCommandLine write SetCommandLine;<br>&nbsp; &nbsp; property ShowWindow: integer read FShowWindow write SetShowWindow default<br>&nbsp; &nbsp; &nbsp; SW_SHOWDEFAULT;<br>&nbsp; &nbsp; property DefaultErrorMode: boolean read FDefaultErrorMode write<br>&nbsp; &nbsp; &nbsp; SetDefaultErrorMode;<br>&nbsp; &nbsp; property StartSuspended: boolean read FStartSuspended write<br>&nbsp; &nbsp; &nbsp; SetStartSuspended;<br>&nbsp; &nbsp; property InitialPriority: TPriorityClass read FInitialPriority write<br>&nbsp; &nbsp; &nbsp; SetInitialPriority;<br>&nbsp; &nbsp; property Directory: string read FDirectory write SetDirectory;<br>&nbsp; &nbsp; property OnData: TDataEvent read FOnData write FOnData;<br>&nbsp; &nbsp; property OnErrorData: TDataEvent read FOnErrorData write FOnErrorData;<br>&nbsp; &nbsp; property OnTerminated: TNotifyEvent read FOnTerminated write FOnTerminated;<br>&nbsp; end;<br><br>implementation<br><br>const<br>&nbsp; DUPLICATE_CLOSE_SOURCE = 1;<br>&nbsp; DUPLICATE_SAME_ACCESS = 2;<br><br>type<br>&nbsp; TRedirectorThread = class(TThread)<br>&nbsp; protected<br>&nbsp; &nbsp; FRedirector: TRedirector;<br>&nbsp; &nbsp; procedure Execute; override;<br>&nbsp; &nbsp; constructor Create(ARedirector: TRedirector);<br>&nbsp; end;<br><br>&nbsp; ////////////////////////////////////////////////////////////////////////////////<br>&nbsp; // Misc. internal methods<br>&nbsp; ////////////////////////////////////////////////////////////////////////////////<br><br>procedure TRedirector.Error(msg: string);<br>begin<br>&nbsp; TerminateProcess(ProcessHandle, 0);<br>&nbsp; raise Exception.Create(msg);<br>end;<br><br>procedure TRedirector.WinError(msg: string);<br>begin<br>&nbsp; Error(msg + IntToStr(GetLastError));<br>end;<br><br>procedure TRedirector.CreatePipes;<br>var<br>&nbsp; SecAttr: TSecurityAttributes;<br>begin<br>&nbsp; SecAttr.nLength := SizeOf(SecAttr);<br>&nbsp; SecAttr.lpSecurityDescriptor := nil;<br>&nbsp; SecAttr.bInheritHandle := TRUE;<br><br>&nbsp; with FPipeInput do<br>&nbsp; begin<br>&nbsp; &nbsp; if not CreatePipe(hRead, hWrite, @SecAttr, 1024) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDIN pipe creation : ');<br>&nbsp; &nbsp; if not DuplicateHandle(GetCurrentProcess, hRead, GetCurrentProcess,<br>&nbsp; &nbsp; &nbsp; @hRead, 0, TRUE, DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDIN pipe duplication : ');<br>&nbsp; end;<br>&nbsp; with FPipeOutput do<br>&nbsp; begin<br>&nbsp; &nbsp; if not CreatePipe(hRead, hWrite, @SecAttr, 1024) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDOUT pipe creation : ');<br>&nbsp; &nbsp; if not DuplicateHandle(GetCurrentProcess, hWrite, GetCurrentProcess,<br>&nbsp; &nbsp; &nbsp; @hWrite, 0, TRUE, DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDOUT pipe duplication : ');<br>&nbsp; end;<br>&nbsp; with FPipeError do<br>&nbsp; begin<br>&nbsp; &nbsp; if not CreatePipe(hRead, hWrite, @SecAttr, 1024) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDERR pipe creation : ');<br>&nbsp; &nbsp; if not DuplicateHandle(GetCurrentProcess, hWrite, GetCurrentProcess,<br>&nbsp; &nbsp; &nbsp; @hWrite, 0, TRUE, DUPLICATE_CLOSE_SOURCE or DUPLICATE_SAME_ACCESS) then<br>&nbsp; &nbsp; &nbsp; WinError('Error on STDERR pipe duplication : ');<br>&nbsp; end;<br>end;<br><br>procedure TRedirector.ClosePipes;<br>begin<br>&nbsp; with FPipeInput do<br>&nbsp; begin<br>&nbsp; &nbsp; if hRead &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hRead);<br>&nbsp; &nbsp; if hWrite &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hWrite);<br>&nbsp; &nbsp; hRead := 0;<br>&nbsp; &nbsp; hWrite := 0;<br>&nbsp; end;<br>&nbsp; with FPipeOutput do<br>&nbsp; begin<br>&nbsp; &nbsp; if hRead &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hRead);<br>&nbsp; &nbsp; if hWrite &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hWrite);<br>&nbsp; &nbsp; hRead := 0;<br>&nbsp; &nbsp; hWrite := 0;<br>&nbsp; end;<br>&nbsp; with FPipeError do<br>&nbsp; begin<br>&nbsp; &nbsp; if hRead &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hRead);<br>&nbsp; &nbsp; if hWrite &lt;&gt; 0 then<br>&nbsp; &nbsp; &nbsp; CloseHandle(hWrite);<br>&nbsp; &nbsp; hRead := 0;<br>&nbsp; &nbsp; hWrite := 0;<br>&nbsp; end;<br>end;<br><br>////////////////////////////////////////////////////////////////////////////////<br>// Property implementations<br>////////////////////////////////////////////////////////////////////////////////<br><br>function TRedirector.GetRunning: boolean;<br>begin<br>&nbsp; Result := ProcessHandle &lt;&gt; 0;<br>end;<br><br>function TRedirector.GetExitCode: integer;<br>begin<br>&nbsp; if Running then<br>&nbsp; &nbsp; Result := STILL_ACTIVE<br>&nbsp; else<br>&nbsp; &nbsp; Result := FExitCode;<br>end;<br><br>function TRedirector.GetProcessID: integer;<br>begin<br>&nbsp; Result := FProcessInfo.dwProcessID;<br>end;<br><br>function TRedirector.GetThreadID: integer;<br>begin<br>&nbsp; Result := FProcessInfo.dwThreadID;<br>end;<br><br>function TRedirector.GetProcessHandle: integer;<br>begin<br>&nbsp; Result := FProcessInfo.hProcess;<br>end;<br><br>function TRedirector.GetThreadHandle: integer;<br>begin<br>&nbsp; Result := FProcessInfo.hThread;<br>end;<br><br>procedure TRedirector.SetExecutable(value: string);<br>begin<br>&nbsp; if (ANSICompareText(value, Executable) = 0) or not Running then<br>&nbsp; &nbsp; FExecutable := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change Executable while process is active');<br>end;<br><br>procedure TRedirector.SetCommandLine(value: string);<br>begin<br>&nbsp; if (ANSICompareText(value, Commandline) = 0) or not Running then<br>&nbsp; &nbsp; FCommandline := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change Commandline while process is active');<br>end;<br><br>function TRedirector.GetCommandLine: string;<br>begin<br>&nbsp; Result := FExecutable;<br>&nbsp; if Result = '' then<br>&nbsp; &nbsp; Result := FCommandline<br>&nbsp; else<br>&nbsp; &nbsp; Result := FExecutable + ' ' + FCommandline;<br>end;<br><br>procedure TRedirector.SetDefaultErrorMode(value: boolean);<br>begin<br>&nbsp; if (value = DefaultErrorMode) or not Running then<br>&nbsp; &nbsp; FDefaultErrorMode := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change DefaultErrorMode while process is active');<br>end;<br><br>procedure TRedirector.SetStartSuspended(value: boolean);<br>begin<br>&nbsp; if (value = DefaultErrorMode) or not Running then<br>&nbsp; &nbsp; FStartSuspended := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change StartSuspended while process is active');<br>end;<br><br>procedure TRedirector.SetInitialPriority(value: TPriorityClass);<br>begin<br>&nbsp; if (value = InitialPriority) or not Running then<br>&nbsp; &nbsp; FInitialPriority := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change InititalPriority while process is active');<br>end;<br><br>procedure TRedirector.SetDirectory(value: string);<br>begin<br>&nbsp; if (ANSICompareText(value, Directory) = 0) or (not Running) then<br>&nbsp; &nbsp; FDirectory := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change Directory while process is active');<br>end;<br><br>procedure TRedirector.SetEnvironment(value: pointer);<br>begin<br>&nbsp; if (value = Environment) or not Running then<br>&nbsp; &nbsp; FEnvironment := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change Environment while process is active');<br>end;<br><br>procedure TRedirector.SetShowWindow(value: integer);<br>begin<br>&nbsp; if (value = ShowWindow) or not Running then<br>&nbsp; &nbsp; FShowWindow := value<br>&nbsp; else if Running then<br>&nbsp; &nbsp; Error('Cannot change ShowWindow while process is active');<br>end;<br><br>procedure TRedirector.ReadStdOutput;<br>var<br>&nbsp; BytesRead: DWORD;<br>&nbsp; buffer: pointer;<br>begin<br>&nbsp; GetMem(Buffer, FAvailable);<br>&nbsp; try<br>&nbsp; &nbsp; if not ReadFile(FPipeOutput.hRead, buffer^, FAvailable, BytesRead, nil) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FThread.Terminate;<br>&nbsp; &nbsp; &nbsp; WinError('Error reading STDOUT pipe : ');<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if Assigned(FOnData) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FOnData(Self, buffer, BytesRead);<br>&nbsp; &nbsp; end;<br>&nbsp; finally<br>&nbsp; &nbsp; FreeMem(buffer);<br>&nbsp; end;<br>end;<br><br>procedure TRedirector.ReadStdError;<br>var<br>&nbsp; BytesRead: DWORD;<br>&nbsp; buffer: pointer;<br>begin<br>&nbsp; GetMem(Buffer, FAvailable);<br>&nbsp; try<br>&nbsp; &nbsp; if not ReadFile(FPipeError.hRead, buffer^, FAvailable, BytesRead, nil) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FThread.Terminate;<br>&nbsp; &nbsp; &nbsp; WinError('Error reading STDERR pipe : ');<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if Assigned(FOnErrorData) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FOnErrorData(Self, buffer, BytesRead);<br>&nbsp; &nbsp; end;<br>&nbsp; finally<br>&nbsp; &nbsp; FreeMem(buffer);<br>&nbsp; end;<br>end;<br><br>procedure TRedirector.ProcessTerminated;<br>begin<br>&nbsp; FThread.Terminate;<br>&nbsp; if Assigned(FOnTerminated) then<br>&nbsp; &nbsp; FOnTerminated(Self);<br>&nbsp; ClosePipes;<br>&nbsp; CloseHandle(FProcessInfo.hProcess);<br>&nbsp; CloseHandle(FProcessInfo.hThread);<br>&nbsp; FillChar(FProcessInfo, SizeOf(FProcessInfo), 0);<br>end;<br><br>////////////////////////////////////////////////////////////////////////////////<br>// Public methods<br>////////////////////////////////////////////////////////////////////////////////<br><br>procedure TRedirector.Terminate(dwExitCode: integer);<br>begin<br>&nbsp; if Running then<br>&nbsp; &nbsp; TerminateProcess(ProcessHandle, dwExitCode)<br>&nbsp; else<br>&nbsp; &nbsp; Error('Cannot Terminate an inactive process');<br>end;<br><br>procedure TRedirector.Execute;<br>var<br>&nbsp; StartupInfo: TStartupInfo;<br>&nbsp; szExecutable,<br>&nbsp; &nbsp; szCommandline,<br>&nbsp; &nbsp; szDirectory: PChar;<br>begin<br>&nbsp; if Running then<br>&nbsp; &nbsp; Error('Process is already active');<br>&nbsp; if Trim(CommandLine) = '' then<br>&nbsp; &nbsp; Error('No commandline to run');<br>&nbsp; try<br>&nbsp; &nbsp; CreatePipes;<br><br>&nbsp; &nbsp; FillChar(StartupInfo, SizeOf(StartupInfo), 0);<br>&nbsp; &nbsp; StartupInfo.cb := SizeOf(StartupInfo);<br><br>&nbsp; &nbsp; StartupInfo.wShowWindow := FShowWindow;<br>&nbsp; &nbsp; StartupInfo.hStdInput := FPipeInput.hRead;<br>&nbsp; &nbsp; StartupInfo.hStdOutput := FPipeOutput.hWrite;<br>&nbsp; &nbsp; StartupInfo.hStdError := FPipeError.hWrite;<br>&nbsp; &nbsp; StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;<br><br>&nbsp; &nbsp; if Trim(Executable) = '' then<br>&nbsp; &nbsp; &nbsp; szExecutable := nil<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; szExecutable := PChar(FExecutable);<br>&nbsp; &nbsp; if Trim(Commandline) = '' then<br>&nbsp; &nbsp; &nbsp; szCommandline := nil<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; szCommandline := PChar(FCommandline);<br>&nbsp; &nbsp; if Trim(Directory) = '' then<br>&nbsp; &nbsp; &nbsp; szDirectory := nil<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; szDirectory := PChar(FDirectory);<br>&nbsp; &nbsp; if CreateProcess(<br>&nbsp; &nbsp; &nbsp; szExecutable,<br>&nbsp; &nbsp; &nbsp; szCommandline,<br>&nbsp; &nbsp; &nbsp; nil,<br>&nbsp; &nbsp; &nbsp; nil,<br>&nbsp; &nbsp; &nbsp; TRUE,<br>&nbsp; &nbsp; &nbsp; (CREATE_DEFAULT_ERROR_MODE and integer(FDefaultErrorMode))<br>&nbsp; &nbsp; &nbsp; or (CREATE_SUSPENDED and integer(FStartSuspended)),<br>&nbsp; &nbsp; &nbsp; Environment,<br>&nbsp; &nbsp; &nbsp; szDirectory,<br>&nbsp; &nbsp; &nbsp; StartupInfo,<br>&nbsp; &nbsp; &nbsp; FProcessInfo) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; //WaitForSingleObject(FProcessInfo.hProcess, 5000);<br>&nbsp; &nbsp; &nbsp; FThread := TRedirectorThread.Create(Self);<br>&nbsp; &nbsp; end<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; WinError('Error creating process : ');<br>&nbsp; except<br>&nbsp; &nbsp; on Exception do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; ClosePipes;<br>&nbsp; &nbsp; &nbsp; CloseHandle(FProcessInfo.hProcess);<br>&nbsp; &nbsp; &nbsp; CloseHandle(FProcessInfo.hThread);<br>&nbsp; &nbsp; &nbsp; FillChar(FProcessInfo, SizeOf(FProcessInfo), 0);<br>&nbsp; &nbsp; &nbsp; raise;<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br><br>procedure TRedirector.SendData(Buffer: pointer; BufferSize: integer);<br>var<br>&nbsp; BytesWritten: DWORD;<br>begin<br>&nbsp; if not Running then<br>&nbsp; &nbsp; Error('Can''t send data to an inactive process');<br>&nbsp; if not WriteFile(FPipeInput.hWrite, Buffer^, BufferSize, BytesWritten, nil)<br>&nbsp; &nbsp; then<br>&nbsp; &nbsp; WinError('Error writing to STDIN pipe : ');<br>end;<br><br>procedure TRedirector.SendText(s: string);<br>begin<br>&nbsp; SendData(PChar(s), Length(s));<br>end;<br><br>destructor TRedirector.Destroy;<br>begin<br>&nbsp; if Running and KillOnDestroy then<br>&nbsp; begin<br>&nbsp; &nbsp; FOnTerminated := nil;<br>&nbsp; &nbsp; FThread.Terminate;<br>&nbsp; &nbsp; Terminate(0);<br>&nbsp; end;<br>&nbsp; inherited Destroy;<br>end;<br><br>constructor TRedirectorThread.Create(ARedirector: TRedirector);<br>begin<br>&nbsp; FRedirector := ARedirector;<br>&nbsp; inherited Create(FALSE);<br>end;<br><br>procedure TRedirectorThread.Execute;<br>var<br>&nbsp; Idle: boolean;<br>begin<br>&nbsp; FreeOnTerminate := TRUE;<br>&nbsp; while not Terminated do<br>&nbsp; begin<br>&nbsp; &nbsp; Idle := TRUE;<br>&nbsp; &nbsp; if PeekNamedPipe(FRedirector.FPipeOutput.hRead, nil, 0, nil,<br>&nbsp; &nbsp; &nbsp; @FRedirector.FAvailable, nil) and (FRedirector.FAvailable &gt; 0) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Synchronize(FRedirector.ReadStdOutput);<br>&nbsp; &nbsp; &nbsp; Idle := FALSE;<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if PeekNamedPipe(FRedirector.FPipeError.hRead, nil, 0, nil,<br>&nbsp; &nbsp; &nbsp; @FRedirector.FAvailable, nil) and (FRedirector.FAvailable &gt; 0) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Synchronize(FRedirector.ReadStdError);<br>&nbsp; &nbsp; &nbsp; Idle := FALSE;<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; if Idle and (WaitForSingleObject(FRedirector.ProcessHandle,<br>&nbsp; &nbsp; &nbsp; 100) = WAIT_OBJECT_0) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if not Terminated then<br>&nbsp; &nbsp; &nbsp; &nbsp; Synchronize(FRedirector.ProcessTerminated);<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br><br>end.<br><br>//--------------------------------------------------------------------------------------<br>
 
to HD_Copy:<br>&nbsp; 你给的那个uRedirector我试了一下,在Win9x/Me下对付Command.com确实没问题,<br>但是在对付象perl或者php还有我写的一个很简单的测试程序时,仍然工作不正常。<br>我的测试程序如下:<br><br>program testpipe;<br>var s: string;<br>begin<br>&nbsp; read(s);write(s);<br>end.<br><br>这类程序大多是调用ReadFile函数读数据,直到缓冲区满了或者文件(管道)结束,<br>ReadFile才返回。在WinNT/XP下,关闭管道的一端时,对管道另一端的程序来说,<br>文件就结束了,于是ReadFile返回。但是在Win9x下,管道另一端的程序似乎检测不<br>到文件的结束,于是继续等待……,程序挂起。而Command.com似乎不是这样的原<br>理……。<br><br>总之目前为止,在Win9x/Me系统下我仍然无法用管道向被调用进程的标准输入写数据<br>(command.com除外)。:(<br><br>不过,活人当然不能让尿憋死,因为就我的需求来说,主要是向被执行的子程序输出<br>数据,然后从子程序接收数据。这样的话,不用管道,使用临时文件来做重定向,也<br>可以达到要求:)。<br><br>晚一点再贴出我的代码。
 
好久没怎么来了,忘了还有未结的贴子:)
 
后退
顶部