程序中调用dos程序并截获该程序的所有输出(100分征求!) (100分)

  • 主题发起人 主题发起人 步惊云
  • 开始时间 开始时间

步惊云

Unregistered / Unconfirmed
GUEST, unregistred user!
我想在主线程中调用一个dos界面的程序,并把该程序的所有输出(正常信息,错误信息)
全部log到一个文件中。调用程序简单,用ShellExecute或CreateProcess就可以,只
是如何获得它的输出呢?
我已试过,这个程序很怪,无论用 > 还是 >> 还是 2>, 都只能收集到一小部分输出,但
我要全部在屏幕上显示的输出都被log下来. 在该dos程序中,似乎调用了另外几个程序,
并把这些程序的输出都重定向到了自己的窗口中,可能因为这个原因,才使正常的重定向
不能生效.
 
用pipe,下面是个例子:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
hReadPipe,hWritePipe:THandle;
si:STARTUPINFO;
lsa:SECURITY_ATTRIBUTES;
pi:PROCESS_INFORMATION;
mDosScreen:String;
cchReadBuffer:DWORD;
ph:PChar;
fname:PChar;
i,j:integer;
begin
fname:=allocmem(255);
ph:=AllocMem(5000);
lsa.nLength :=sizeof(SECURITY_ATTRIBUTES);
lsa.lpSecurityDescriptor :=nil;
lsa.bInheritHandle :=True;
if CreatePipe(hReadPipe,hWritePipe,@lsa,0)=false then
begin
ShowMessage('Can not create pipe!');
exit;
end;

fillchar(si,sizeof(STARTUPINFO),0);
si.cb :=sizeof(STARTUPINFO);
si.dwFlags :=(STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW);
si.wShowWindow :=SW_HIDE;
si.hStdOutput :=hWritePipe;
StrPCopy(fname,'nbtstat -a 192.168.0.15');
if CreateProcess( nil, fname, nil, nil, true, 0, nil, nil, si, pi) = False then
begin
ShowMessage('can not create process');
FreeMem(ph);
FreeMem(fname);
Exit;
end;

while(true)do
begin
if not PeekNamedPipe(hReadPipe,ph,1,@cchReadBuffer,nil,nil) then
break;
if cchReadBuffer<>0 then
begin
if ReadFile(hReadPipe,ph^,4096,cchReadBuffer,nil)=false then
break;
ph[cchReadbuffer]:=chr(0);
Memo1.Lines.Add(ph);
end
else
if(WaitForSingleObject(pi.hProcess ,0)=WAIT_OBJECT_0) then
break;
Sleep(100);
end;

ph[cchReadBuffer]:=chr(0);
Memo1.Lines.Add(ph);
CloseHandle(hReadPipe);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hWritePipe);
FreeMem(ph);
FreeMem(fname);
end;

end.
 
用 pipe 好像不能解决我的问题,因为问题是怎么收集不到该程序的输出,而不是无法log
这些信息.
另外,我的程序是VC的.
 
demoReadConOut, 参考一下吧,我也没用过。
/******************************************************************************/
* This is a part of the Microsoft Source Code Samples.
* Copyright (C) 1993-1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelpdo
cumentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
/******************************************************************************/
#include <windows.h>
#include <string.h>
#include <malloc.h>
#include "console.h"
/********************************************************************
* FUNCTION: invertRectangle(HANDLE hConOut, COORD coordStart, *
* COORD coordCur) *
* *
* PURPOSE: invert the attributes of the rectangle defined as the *
* area between two input COORD parameters *
* *
* INPUT: the output handle of the console to make the changes to, *
* and two sets of COORD structures defining the rectangle to *
* invert *
********************************************************************/
void invertRectangle(HANDLE hConOut, COORD coordStart, COORD coordCur)
{
WORD *awLineAttr;
unsigned i;
DWORD dwBoxWidth;
WORD top, left, right, bottom;
BOOL bSuccess;
DWORD dwNumAttrsRead;
/* convert coordSart to upper left &amp;
coordCur to lower right */
top = min(coordStart.Y, coordCur.Y);
bottom = max(coordStart.Y, coordCur.Y);
left = min(coordStart.X, coordCur.X);
right = max(coordStart.X, coordCur.X);
coordStart.X = left;
coordStart.Y = top;
coordCur.X = right;
coordCur.Y = bottom;
/* get the width of the selected area */
dwBoxWidth = right - left + 1;
/* allocate a buffer for the attributes read from the console */
awLineAttr = (PWORD) malloc(getConX(hConOut) * sizeof(DWORD));
PERR(awLineAttr, "malloc");
/* for each line in the selected area */
while (coordStart.Y <= coordCur.Y)
{
/* read the attributes on that line */
bSuccess = ReadConsoleOutputAttribute(hConOut, awLineAttr,
dwBoxWidth, coordStart, &amp;dwNumAttrsRead);
PERR(bSuccess, "ReadConsoleOutputAttribute");
/* for each attribute in the line, invert the color */
for (i = 0;
i < dwBoxWidth;
i++)
awLineAttr = ~awLineAttr;
/* put the inverted color back on the line */
bSuccess = WriteConsoleOutputAttribute(hConOut, awLineAttr, dwBoxWidth,
coordStart, &amp;dwNumAttrsRead);
PERR(bSuccess, "WriteConsoleOutputAttribute");
coordStart.Y++;
/* go to the next line */
}
free(awLineAttr);
/* free allocated attribute buffer */
return;
}

/********************************************************************
* FUNCTION: demoReadConOut(HANDLE hConOut) *
* *
* PURPOSE: demonstrate ReadConsoleOutput, WriteConsoleOutput, *
* ReadConsoleOutputAttribute, and *
* WriteConsoleOutputAttribute. Implement a cut and past *
* function;
as the user clicks and drags the mouse, invert *
* the selection rectangle to show the area selected. When *
* the mouse button is released, copy the selected area and *
* paste it to the console *
* *
* INPUT: the output handle to read from and write to *
********************************************************************/
void demoReadConOut(HANDLE hConOut)
{
BOOL bSuccess;
INPUT_RECORD inputBuffer;
DWORD dwStdInMode;
HANDLE hStdIn;
DWORD dwInputEvents;
COORD coordStart, coordEnd, coordDest = {0, 0};
BOOL bDragMode = FALSE;
/* mode flag - selecting (dragging) or not? */
COORD coordPrev;
/* coordinates of the start of the selected area */
CHAR_INFO *pCharInfo;
/* buffer to store info from ReadConsoleOutput */
COORD coordBufSize;
/* the size of the buffer to read into */
SMALL_RECT srReadRegion;
/* source rectangle to read from */
WORD top, left, right, bottom;
/* sides of the source rectangle */
CONSOLE_SCREEN_BUFFER_INFO csbi;
/* used to get cursor position */
setConTitle(__FILE__);
myPuts(hConOut, "Let's implement a simple cut &amp;
paste with the left mouse/n"
"button. Click and drag to select an area of the screen/n"
"to copy. We will read, invert, then
write the screen attributes/n"
"of the area you are dragging over to show the current/n"
"selection. Release the mouse button and I will read the/n"
"screen contained in the output area and print the contents/n"
"of the buffer to the screen at the current cursor location./n"
"Hit ESC to return./n/n");
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
PERR(hStdIn != INVALID_HANDLE_VALUE, "GetStdHandle");
/* save the console mode */
bSuccess = GetConsoleMode(hStdIn, &amp;dwStdInMode);
PERR(bSuccess, "GetConsoleMode");
/* enable mouse input */
bSuccess = SetConsoleMode(hStdIn, dwStdInMode | ENABLE_MOUSE_INPUT);
PERR(bSuccess, "SetConsoleMode");
for(;;)
{
/* get an input event */
bSuccess = ReadConsoleInput(hStdIn, &amp;inputBuffer, 1, &amp;dwInputEvents);
PERR(bSuccess, "ReadConsoleInput");
switch (inputBuffer.EventType)
{
case KEY_EVENT:
/* is it an ESC character? */
if (inputBuffer.Event.KeyEvent.bKeyDown &amp;&amp;
inputBuffer.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
{
/* set input mode back to what it was originally and return */
bSuccess = SetConsoleMode(hStdIn, dwStdInMode);
PERR(bSuccess, "SetConsoleMode");
return;
}
break;
case MOUSE_EVENT:
/* was this was a click event? */
if (inputBuffer.Event.MouseEvent.dwEventFlags != MOUSE_MOVED)
/* is only leftmost buttondo
wn? */
{
if(inputBuffer.Event.MouseEvent.dwButtonState ==
FROM_LEFT_1ST_BUTTON_PRESSED)
{
/* save the starting coordinates of the selected area */
coordStart = coordPrev =
inputBuffer.Event.MouseEvent.dwMousePosition;
/* invert the single char attribute the cursor is on */
invertRectangle(hConOut, coordStart, coordStart);
bDragMode = TRUE;
/* we are now in 'drag' mode */
}
else
/* button #1 has just been released */
{
/* if we're not in drag mode, break;
we might get a mouse */
/* button release when gaining the focus */
if (!bDragMode)
break;
/* save the coordinates of the mouse release */
coordEnd = inputBuffer.Event.MouseEvent.dwMousePosition;
bDragMode = FALSE;
/* we're not in 'drag' mode anymore */
/* invert the rectangle back to normal */
invertRectangle(hConOut, coordStart, coordEnd);
/* copy the buffer in the rectangle and output it. First convert */
/* coordSart to upper left &amp;
coordCur to lower right */
top = min(coordStart.Y, coordend.
Y);
left = min(coordStart.X, coordend.
X);
bottom = max(coordStart.Y, coordend.
Y);
right = max(coordStart.X, coordend.
X);
coordStart.X = srReadRegion.Left = left;
coordStart.Y = srReadRegion.Top = top;
coordend.
X = srReadRegion.Right = right;
coordend.
Y = srReadRegion.Bottom = bottom;
/* get the size of the selected rectangle */
coordBufSize.X = coordend.
X - coordStart.X + (SHORT) 1;
coordBufSize.Y = coordend.
Y - coordStart.Y + (SHORT) 1;
/* allocate a buffer for the screen rectangle */
pCharInfo = malloc(coordBufSize.X * coordBufSize.Y *
sizeof(CHAR_INFO));
PERR(pCharInfo, "malloc");
/* read the screen rectangle into the buffer */
bSuccess = ReadConsoleOutput(hConOut, /* output buffer */
pCharInfo, /* buffer that receives data */
coordBufSize, /* col/row size of destination buffer */
coordDest, /* upper-left cell to write data to in dest */
&amp;srReadRegion);
/* screen buffer rectangle to read from */
PERR(bSuccess, "ReadConsoleOutput");
/* get current cursor position */
bSuccess = GetConsoleScreenBufferInfo(hConOut, &amp;csbi);
PERR(bSuccess, "GetConsoleScreenBufferInfo");
/* set up an output destination rectangle for the buffer. */
/* Put it just below the current cursor position. */
srReadRegion.Top = csbi.dwCursorPosition.Y;
srReadRegion.Bottom = csbi.dwCursorPosition.Y + (bottom - top);
srReadRegion.Left = 0;
srReadRegion.Right = right - left;
bSuccess = WriteConsoleOutput(hConOut, /* output buffer */
pCharInfo, /* buffer with data to write */
coordBufSize, /* col/row size of source buffer */
coordDest, /* upper-left cell to write data from in src */
&amp;srReadRegion);
/* screen buffer rect to write data to */
PERR(bSuccess, "WriteConsoleOutput");
free(pCharInfo);
}
}
/* is it a mouse movement while we are in drag mode? */
if (inputBuffer.Event.MouseEvent.dwEventFlags == MOUSE_MOVED &amp;&amp;
bDragMode)
{
/* if the cursor moves from the rectangle it was previously in, */
/* invert the old rectangle then
invert the new rectangle. */
/* Compare the current coordinates with the previous coordinates */
if (memcmp(&amp;inputBuffer.Event.MouseEvent.dwMousePosition,
&amp;coordPrev, sizeof(COORD)))
{
/* You could be clever and only invert what needs to be */
/* inverted rather than the entire two rectangles... */
/* Invert the old rectangle */
invertRectangle(hConOut, coordStart, coordPrev);
/* and invert the new rectangle */
invertRectangle(hConOut, coordStart,
inputBuffer.Event.MouseEvent.dwMousePosition);
/* save the current mouse position to the previous position */
memcpy(&amp;coordPrev,
&amp;inputBuffer.Event.MouseEvent.dwMousePosition,
sizeof(COORD));
}
}
break;
} /* switch */
} /* while */
}
 
以前的帖子都讨论N遍了[:(]
 
接受答案了.
 
基本搞定,大致方法是创建anonymous管道,将子进程的输出重定向到管道的
写,在主进程中读管道的读,但实际做起来有很多细节要注意的。
可参看 http://codeguru.earthweb.com/misc/redirect.shtml
 
后退
顶部