我用这个函数建立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'主程序读取不到
奇怪的是,如果关闭了被调用的程序,这些数据主程序就一批读到了
是不是要强制刷新管道中的数据?

解决方案 »

  1.   

          // Get std input handle so you can close it and force the ReadFile to
          // 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.
      

  2.   


          // 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  
     
     
      帮助