我用这个函数建立pipe
procedure CreatAPipe(Var HRead, HWrite: THandle);
var
sa : TSecurityAttributes;
b : Boolean;
begin
FillChar(sa, sizeof(sa), 0);
//设置允许继承,否则在NT和2000下无法取得输出结果
sa.nLength := sizeof(sa);
sa.bInheritHandle := True;
sa.lpSecurityDescriptor := nil;
b := CreatePipe(HRead, HWrite, @sa, 1);
CheckResult(b);
end;
然后调用一个外部程序
procedure TForm1.Button5Click(Sender: TObject);
var
MYin, CGIout : THandle;
MYout,CGIin : THandle;
StartInfo : TStartupInfo;
ProceInfo : TProcessInformation;
b : Boolean;
buf: array[0..1024] of char; //i/o buffer
c:char;
i:integer;
vexit,bread,avail: cardinal; //bytes available
s:string;
begin
CreatAPipe(MYin, CGIout);
CreatAPipe(CGIin, MYout); FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb := SizeOf(StartInfo);
StartInfo.wShowWindow := SW_SHOW;
//使用指定的句柄作为标准输入输出的文件句柄,使用指定的显示方式
StartInfo.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
StartInfo.hStdError := CGIout;
StartInfo.hStdInput := CGIin;
StartInfo.hStdOutput := CGIout; b := CreateProcess(PChar(Edit1.Text), //lpApplicationName: PChar
PChar(PChar(Edit2.Text)), //lpCommandLine: PChar
nil, //lpProcessAttributes: PSecurityAttributes
nil, //lpThreadAttributes: PSecurityAttributes
True, //bInheritHandles: BOOL
CREATE_NEW_CONSOLE,
nil,
PChar('d:\'),
StartInfo,
ProceInfo); CheckResult(b);
s:='abcdef';
for i:=1 to length(s) do //
begin
buf[0]:=s[i];
WriteFile(MYout,buf,1,bread,nil);
ReadFile(MYin,buf,1,bread,nil);
s[i]:=buf[0];
end;
Form1.Memo1.Lines.Append(s);
Form1.Memo1.Lines.Append('-------------------------');
end;用管道连接外部程序之后,希望主程序通过管道发送字符到外部程序,
外部程序处理之后返回结果外部程序主要为:procedure TForm1.Button1Click(Sender: TObject);
var
c:char;
begin
Button1.Enabled:=false;
read(c);//读取数据
if (c>='a') then
c:=//做一些需要的变换,譬如改变大小写
write(c);返回数据
//write('K');//测试用的
Button1.Enabled:=true;
end;结果感觉两个程序配合不起来,好像一方将数据写入管道了,另外一方却读不到数据测试时候我尝试被调用的程序不读取,只是返回'k',结果也发现这些'k'主程序读取不到
奇怪的是,如果关闭了被调用的程序,这些数据主程序就一批读到了
是不是要强制刷新管道中的数据?
procedure CreatAPipe(Var HRead, HWrite: THandle);
var
sa : TSecurityAttributes;
b : Boolean;
begin
FillChar(sa, sizeof(sa), 0);
//设置允许继承,否则在NT和2000下无法取得输出结果
sa.nLength := sizeof(sa);
sa.bInheritHandle := True;
sa.lpSecurityDescriptor := nil;
b := CreatePipe(HRead, HWrite, @sa, 1);
CheckResult(b);
end;
然后调用一个外部程序
procedure TForm1.Button5Click(Sender: TObject);
var
MYin, CGIout : THandle;
MYout,CGIin : THandle;
StartInfo : TStartupInfo;
ProceInfo : TProcessInformation;
b : Boolean;
buf: array[0..1024] of char; //i/o buffer
c:char;
i:integer;
vexit,bread,avail: cardinal; //bytes available
s:string;
begin
CreatAPipe(MYin, CGIout);
CreatAPipe(CGIin, MYout); FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb := SizeOf(StartInfo);
StartInfo.wShowWindow := SW_SHOW;
//使用指定的句柄作为标准输入输出的文件句柄,使用指定的显示方式
StartInfo.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
StartInfo.hStdError := CGIout;
StartInfo.hStdInput := CGIin;
StartInfo.hStdOutput := CGIout; b := CreateProcess(PChar(Edit1.Text), //lpApplicationName: PChar
PChar(PChar(Edit2.Text)), //lpCommandLine: PChar
nil, //lpProcessAttributes: PSecurityAttributes
nil, //lpThreadAttributes: PSecurityAttributes
True, //bInheritHandles: BOOL
CREATE_NEW_CONSOLE,
nil,
PChar('d:\'),
StartInfo,
ProceInfo); CheckResult(b);
s:='abcdef';
for i:=1 to length(s) do //
begin
buf[0]:=s[i];
WriteFile(MYout,buf,1,bread,nil);
ReadFile(MYin,buf,1,bread,nil);
s[i]:=buf[0];
end;
Form1.Memo1.Lines.Append(s);
Form1.Memo1.Lines.Append('-------------------------');
end;用管道连接外部程序之后,希望主程序通过管道发送字符到外部程序,
外部程序处理之后返回结果外部程序主要为:procedure TForm1.Button1Click(Sender: TObject);
var
c:char;
begin
Button1.Enabled:=false;
read(c);//读取数据
if (c>='a') then
c:=//做一些需要的变换,譬如改变大小写
write(c);返回数据
//write('K');//测试用的
Button1.Enabled:=true;
end;结果感觉两个程序配合不起来,好像一方将数据写入管道了,另外一方却读不到数据测试时候我尝试被调用的程序不读取,只是返回'k',结果也发现这些'k'主程序读取不到
奇怪的是,如果关闭了被调用的程序,这些数据主程序就一批读到了
是不是要强制刷新管道中的数据?
// fail when you want the input thread to exit.
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle"); PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);
// Close pipe handles (do not continue to modify the parent).
// You need to make sure that no handles to the write end of the
// output pipe are maintained in this process or else the pipe will
// not close when the child process exits and the ReadFile will hang.
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete
// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE; if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject"); if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// PrepAndLaunchRedirectedChild
// Sets up STARTUPINFO structure, and launches redirected child.
///////////////////////////////////////////////////////////////////////
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si; // Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
// Use this if you want to hide the child:
// si.wShowWindow = SW_HIDE;
// Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
// use the wShowWindow flags.
// Launch the process that you want to redirect (in this case,
// Child.exe). Make sure Child.exe is in the same directory as
// redirect.c launch redirect from a command line to prevent location
// confusion.
if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
DisplayError("CreateProcess");
// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess;
// Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}
///////////////////////////////////////////////////////////////////////
// ReadAndHandleOutput
// Monitors handle for input. Exits when child exits or pipe breaks.
///////////////////////////////////////////////////////////////////////
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten; while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
} // Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}
///////////////////////////////////////////////////////////////////////
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
///////////////////////////////////////////////////////////////////////
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam; // Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole"); read_buff[nBytesRead] = '\0'; // Follow input with a NULL. if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
} return 1;
}
///////////////////////////////////////////////////////////////////////
// DisplayError
// Displays the error number and corresponding message.
///////////////////////////////////////////////////////////////////////
void DisplayError(char *pszAPI)
{
LPVOID lpvMessageBuffer;
CHAR szPrintBuffer[512];
DWORD nCharsWritten; FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL); wsprintf(szPrintBuffer,
"ERROR: API = %s.\n error code = %d.\n message = %s.\n",
pszAPI, GetLastError(), (char *)lpvMessageBuffer); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
lstrlen(szPrintBuffer),&nCharsWritten,NULL); LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
} //////////////////////////////////////////////////////////////////////
// child.c
// Echoes all input to stdout. This will be redirected by the redirect
// sample. Compile and build child.c as a Win32 Console application and
// put it in the same directory as the redirect sample.
//
#include<windows.h>
#include<stdio.h>
#include<string.h> void main ()
{
FILE* fp;
CHAR szInput[1024];
// Open the console. By doing this, you can send output directly to
// the console that will not be redirected. fp = fopen("CON", "w");
if (!fp) {
printf("Error opening child console - perhaps there is none.\n");
fflush(NULL);
}
else
{ // Write a message direct to the console (will not be redirected). fprintf(fp,"This data is being printed directly to the\n");
fprintf(fp,"console and will not be redirected.\n\n");
fprintf(fp,"Since the standard input and output have been\n");
fprintf(fp,"redirected data sent to and from those handles\n");
fprintf(fp,"will be redirected.\n\n");
fprintf(fp,"To send data to the std input of this process.\n");
fprintf(fp,"Click on the console window of the parent process\n");
fprintf(fp,"(redirect), and enter data from it's console\n\n");
fprintf(fp,"To exit this process send the string 'exit' to\n");
fprintf(fp,"it's standard input\n");
fflush(fp);
} ZeroMemory(szInput,1024);
while (TRUE)
{
gets(szInput);
printf("Child echoing [%s]\n",szInput);
fflush(NULL); // Must flush output buffers or else redirection
// will be problematic.
if (!_stricmp(szInput,"Exit") )
break; ZeroMemory(szInput,strlen(szInput) ); }
}
REFERENCES
MSDN Library SDK documentation: CreateProcess(); STARTUPINFO structure Inherit sample in the Win32 Platform SDK under:
\MSSDK\samples\winbase\ipc\inherit
The information in this article applies to:
Microsoft Win32 Application Programming Interface (API), when used with:
the operating system: Microsoft Windows 95
the operating system: Microsoft Windows 98
the operating system: Microsoft Windows NT 3.51
the operating system: Microsoft Windows NT 4.0
the operating system: Microsoft Windows 2000
the operating system: Microsoft Windows XP
Last Reviewed: 7/13/2004 (5.1)
Keywords: kbAPI kbConsole kbFAQ kbhowto kbIPC kbKernBase KB190351
帮助