精品一区二区三区影院在线午夜_天天躁日日躁狠狠躁AV麻豆_国产午夜福利短视频_中文字幕乱偷无码AV先锋蜜桃_久久精品一二区东京热_国产成人亚洲日韩欧美久久久,国产成人精品久久一区二区三区

Delphi與管道操作

什么是管道?參考《WIN32匯編編程》是這樣描述的
    Windows 引入了多進程和多線程機制。同時也提供了多個進程之間的通信手段,包括剪貼板、DDE、OLE、管道等,和其他通信手段相比,管道有它自己的限制和特點,管道實際上是一段共享內存區,進程把共享消息放在那里。并通過一些 API 提供信息交換。
管道是兩個頭的東西,每個頭各連接一個進程或者同一個進程的不同代碼,按照管道的類別分有兩種管道,匿名的和命名的;按照管道的傳輸方向分也可以分成兩種,單向的雙向的。根據管道的特點,命名管道通常用在網絡環境下不同計算機上運行的進程之間的通信(當然也可以用在同一臺機的不同進程中)它可以是單向或雙向的;而匿名管道只能用在同一臺計算機中,它只能是單向的。匿名管道其實是通過用給了一個指定名字的有名管道來實現的。
使用管道的好處在于:讀寫它使用的是對文件操作的 api,結果操作管道就和操作文件一樣。即使你在不同的計算機之間用命名管道來通信,你也不必了解和自己去實現網絡間通信的具體細節。
使用匿名管道的步驟如下:
使用 CreatePipe 建立兩個管道,得到管道句柄,一個用來輸入,一個用來輸出
準備執行控制臺子進程,首先使用 GetStartupInfo 得到 StartupInfo
使用第一個管道句柄代替 StartupInfo 中的 hStdInput,第二個代替 hStdOutput、hStdError,即標準輸入、輸出、錯誤句柄
使用 CreateProcess 執行子進程,這樣建立的子進程輸入和輸出就被定向到管道中
父進程通過 ReadFile 讀第二個管道來獲得子進程的輸出,通過 WriteFile 寫第一個管道來將輸入寫到子進程
父進程可以通過 PeekNamedPipe 來查詢子進程有沒有輸出
子進程結束后,要通過 CloseHandle 來關閉兩個管道。
下面是具體的說明和定義:

1. 建立匿名管道使用 CreatePipe 原形如下:
BOOL CreatePipe(
PHANDLE hReadPipe, // address of variable for read handle
PHANDLE hWritePipe, // address of variable for write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // pointer to security attributes
DWORD nSize // number of bytes reserved for pipe
);
當管道建立后,結構中指向的 hReadPipe 和 hWritePipe 可用來讀寫管道,當然由于匿名管道是單向的,你只能使用其中的一個句柄,參數中的 SECURITY_ATTRIBUTES 的結構必須填寫,定義如下:typedef struct_SECURITY_ATTRIBUTES{
DWORD nLength: //定義以字節為單位的此結構的長度
LPVOID lpSecurityDescriptor; //指向控制這個對象共享的安全描述符,如果為NULL這個對象將被分配一個缺省的安全描述
BOOL bInheritHandle; //當一個新過程被創建時,定義其返回是否是繼承的.供系統API函數使用.
}SECURITY_ATTRIBUTES;

2. 填寫創建子進程用的 STARTUPINFO 結構,一般我們可以先用 GetStartupInfo 來填寫一個缺省的結構,然后改動我們用得到的地方,它們是:
hStdInput -- 用其中一個管道的 hWritePipe 代替
hStdOutput、hStdError -- 用另一個管道的 hReadPipe 代替
dwFlags -- 設置為 STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW 表示輸入輸出句柄及 wShowWindow 字段有效
wShowWindow -- 設置為 SW_HIDE,這樣子進程執行時不顯示窗口。
填寫好以后,就可以用 CreateProcess 來執行子進程了。

3. 在程序中可以用 PeekNamedPipe 查詢子進程有沒有輸出,原形如下:
OOL PeekNamedPipe(HANDLE hNamedPipe, // handle to pipe to copy from 
LPVOID lpBuffer, // pointer to data buffer
DWORD nBufferSize, // size, in bytes, of data buffer 
LPDWORD lpBytesRead, // pointer to number of bytes read 
LPDWORD lpTotalBytesAvail, // pointer to total number of bytes available 
LPDWORD lpBytesLeftThisMessage // pointer to unread bytes in this message );
我們可以將嘗試讀取 nBuffersize 大小的數據,然后可以通過返回的 BytesRead 得到管道中有多少數據,如果不等于零,則表示有數據可以讀取。

4. 用 ReadFile 和 WriteFile 來讀寫管道,它們的參數是完全一樣的,原形如下:
ReadFile or WriteFile(HANDLE hFile, // handle of file to read 在這里使用管道句柄
LPVOID lpBuffer, // address of buffer that receives data 緩沖區地址
DWORD nNumberOfBytesToRead, // number of bytes to read 準備讀寫的字節數
LPDWORD lpNumberOfBytesRead, // address of number of bytes read,實際讀到的或寫入的字節數
LPOVERLAPPED lpOverlapped // address of structure for data 在這里用 NULL);

5. 用 CloseHandle 關閉管道一和管道二的 hReadPipe和 hWritePipe 這四個句柄。

下面是一個演示DEMO,可以使用MEMO來制作一個控制臺,所使用的技術就是管道

 procedure RunDosInMemo(Que:String;EnMemo:TMemo);
  const
     CUANTOBUFFER = 2000;
  var
    Seguridades         : TSecurityAttributes;
    PaLeer,PaEscribir   : THandle;
    start               : TStartUpInfo;
    ProcessInfo         : TProcessInformation;
    Buffer              : Pchar;
    BytesRead           : DWord;
    CuandoSale          : DWord;
  begin
    //安全描述 可以省略
    with Seguridades do
    begin
      nlength              := SizeOf(TSecurityAttributes);
      binherithandle       := true;
      lpsecuritydescriptor := nil;
    end;
 
    {Creamos el pipe...}
    if Createpipe (PaLeer, PaEscribir, @Seguridades, 0) then
    begin
      //申請緩沖
      Buffer  := AllocMem(CUANTOBUFFER + 1); 
   
      //創建STARTUPINFO
      FillChar(Start,Sizeof(Start),#0);
      start.cb          := SizeOf(start);
      start.hStdOutput  := PaEscribir;
      start.hStdInput   := PaLeer;
      start.dwFlags     := STARTF_USESTDHANDLES +
                           STARTF_USESHOWWINDOW;
      start.wShowWindow := SW_HIDE;
        
      //執行子進程 
      if CreateProcess(nil,
         PChar(Que),
         @Seguridades,
         @Seguridades,
         true,
         NORMAL_PRIORITY_CLASS,
         nil,
         nil,
         start,
         ProcessInfo)
      then
        begin
          {Espera a que termine la ejecucion}
          repeat
            //使用信號量技術來避免CPU時間片被搶占
            CuandoSale := WaitForSingleObject( ProcessInfo.hProcess,100);
            Application.ProcessMessages;
          until (CuandoSale <> WAIT_TIMEOUT);
          {Leemos la Pipe}
          repeat
            BytesRead := 0;
   
            {Llenamos un troncho de la pipe, igual a nuestro buffer}
            //執行標準輸出
            ReadFile(PaLeer,Buffer[0],CUANTOBUFFER,BytesRead,nil);
            {La convertimos en una string terminada en cero}
            Buffer[BytesRead]:= #0;
            {Convertimos caracteres DOS a ANSI}
            OemToAnsi(Buffer,Buffer);
            EnMemo.Text := EnMemo.text + String(Buffer);
          until (BytesRead < CUANTOBUFFER);
        end;
      FreeMem(Buffer);
   
      //釋放資源
      CloseHandle(ProcessInfo.hProcess);
      CloseHandle(ProcessInfo.hThread);
      CloseHandle(PaLeer);
      CloseHandle(PaEscribir);
    end;
  end;
天台县| 江津市| 瑞金市| 孟州市| 祁连县| 周宁县| 潜山县| 开封县| 黄陵县| 临漳县| 蒙自县| 鄂尔多斯市| 沈阳市| 友谊县| 南投县| 卓尼县| 黔江区| 临猗县| 龙胜| 扶余县| 内乡县| 佛教| 汪清县| 武强县| 惠水县| 嘉禾县| 宝山区| 化隆| 江永县| 漳平市| 彭山县| 丹江口市| 栾城县| 健康| 太谷县| 江华| 张家口市| 横峰县| 稻城县| 寿宁县| 云林县|