天天看點

8、程序通信-匿名管道

匿名管道

一個單向,未命名的管道,通常用來在一個父程序和一個子程序間傳輸資料。隻能實作本地機器上兩個程序間的通信,而不能實作跨網絡的通信。

BOOL CreatePipe(

  PHANDLE hReadPipe,                       // read handle

  PHANDLE hWritePipe,                      // write handle

  LPSECURITY_ATTRIBUTES lpPipeAttributes,  // security attributes

  DWORD nSize                              // pipe size

);

CreateProcess 建立程序

建立父程序:

a. CreatePipe:其中第三個參數代表安全屬性結構體SECURITY_ATTRIBUTES的指針,在前幾章的運用中,都是運用了NULL,代表傳回的安全句柄不可以被子程序所繼承。但在本運用中,涉及到的是匿名管道。匿名管道就是父子程序之間的通信,是以結構體必須設定相應的值。子程序要想獲得匿名管道的讀寫句柄,隻能從父程序繼承而來。一旦子程序有了繼承而來的讀寫句柄,就可以和父程序進行通信了。對于機構體SECURITY_ATTRIBUTES,最重要的是第三個參數bInheritHandle,表示Specifies whether the returned handle is inherited when a new process is created. If this member is TRUE, the new process inherits the handle.

b. CreateProcess:如果建立管道成功,則建立子程序,并将管道的讀寫句柄傳遞給子程序。

1.MFC單文檔程式菜單中增加建立管道,讀取資料,寫入資料三項

2.View類中增加成員變量

3.  CreateProcess

倒數第三個參數 [in] Pointer to a STARTUPINFO structure that specifies how the main window for the new process should appear 指向STARTUPINFO結構體的一個指針,用來指定新的程序它的主視窗如何出現

最後一個參數指向PROCESS_INFORMATION結構體的一個指針的傳回值,用來接收新的程序的辨別資訊

PROCESS_INFORMATION

The PROCESS_INFORMATION structure is filled in by the CreateProcess function with information

 about a newly created process and its primary thread.

typedef struct _PROCESS_INFORMATION {

    HANDLE hProcess;

    HANDLE hThread;

    DWORD dwProcessId;

    DWORD dwThreadId;

} PROCESS_INFORMATION;

Members

hProcess //新建立程序的句柄

A handle to the newly created process. The handle is used to specify the process in all

 functions that perform operations on the process object.

hThread //新建立程序主線程的句柄

A handle to the primary thread of the newly created process. The handle is used to specify

the thread in all functions that perform operations on the thread object.

dwProcessId //全局程序辨別符,如果程序結束作業系統可能會将辨別配置設定給其他程序,我們調用辨別的時候要確定程序在運作

A global process identifier that can be used to identify a process. The value is valid from the time the process is created until the time the process is terminated.

dwThreadId //全局線程辨別符

A global thread identifiers that can be used to identify a thread. The value is valid from the

time the thread is created until the time the thread is terminated.

建立匿名管道具體代碼:

SECURITY_ATTRIBUTES sa;

      //總共就三個參數

      sa.bInheritHandle=TRUE; //表示可被子程序所繼承

      sa.lpSecurityDescriptor=NULL; //安全描述符号一般都設定成NULL,即預設描述符

      sa.nLength=sizeof(SECURITY_ATTRIBUTES); //管道長度

      if(!CreatePipe(&hRead,&hWrite,&sa,0))

      {

           MessageBox("建立匿名函數失敗!");

           return;

      }

      //管道建立成功後,接着建立子程序,并将讀寫句柄傳遞給子程序

      STARTUPINFO sui;

      PROCESS_INFORMATION pi;

      //調用ZeroMemory方法将該結構體中的所有成員都置為0,這是因為這個結構體的成員很多,如果開始的時候沒有置為0的話,那它的值是随機的,将這樣的結構體傳給CreateProcess,可能會影響到執行的結果。

      ZeroMemory(&sui,sizeof(STARTUPINFO));

      sui.cb=sizeof(STARTUPINFO); //設定結構體的大小

      sui.dwFlags=STARTF_USESTDHANDLES; //該辨別表示标準輸入句柄,标準輸出句柄和錯誤句柄是有用的

      sui.hStdInput=hRead; //将子程序的輸入句柄設定成父程序的讀句柄

      sui.hStdOutput=hWrite; //将子程序的輸出句柄設定成父程序的寫句柄

      sui.hStdError=GetStdHandle(STD_ERROR_HANDLE); //得到标準錯誤句柄,是父程序的錯誤句柄,該行代碼在本程式中沒有實際的用途意義

//因為是匿名管道,是沒有名稱的管道,隻有通過CreateProcess由上而下的傳遞管道操作句柄。

if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,

           TRUE,0,NULL,NULL,&sui,π))

           MessageBox("建立子程序失敗!");

           CloseHandle(hRead);

           CloseHandle(hWrite);

           //避免在析構函數中再次關閉,析構函數采用:

           //if(hRead) CloseHandle(hRead)

           hRead=NULL;

           hWrite=NULL;

      else

           //建立一個新的程序的時候,系統會建立一個程序核心對象和一個線程核心對象,核心對象都有一個使用基數,初始調用的時候,都設定為1。在CreateProcess傳回之前,該函數打開程序和線程的核心對象,并将程序相關的句柄放置到結構體PROCESS_INFORMATION的hProcess和hThread中,當Process在内部打開這些對象的時候,使得每個對象的使用基數增加到2了。如果在父程序中不需要使用這兩個句柄,就将這個句柄進行關閉,使得使用基數減1。當子程序終結的時候,系統會在将使用基數減1,使得子程序的程序核心對象和線程核心對象的使用基數變為0,這樣核心對象就可以被釋放了。

           CloseHandle(pi.hProcess); //關閉子程序的句柄

           CloseHandle(pi.hThread); //關閉子程序中主線程的句柄

}

父程序寫匿名管道:

char *buf="hello world";

      DWORD dwWrite;

      if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))

           MessageBox("匿名管道寫入資料失敗!");

父程序讀匿名管道:

char buf[100];

      DWORD dwRead;

      if(!ReadFile(hRead,buf,100,&dwRead,NULL))

           MessageBox("匿名管道讀取資料失敗!");

MessageBox(buf);

建立子程序程式:

可以将擷取父程序的匿名管道的讀寫句柄操作放在CView類的OnInitialUpdate方法中實作,該方法是在CView完全構造後調用的第一個方法。代碼如下:

hRead=GetStdHandle(STD_INPUT_HANDLE);

hWrite=GetStdHandle(STD_OUTPUT_HANDLE);

子程序的讀寫匿名管道的代碼和父程序的一樣,這裡不再累述。

    為了讓子程序從衆多繼承的句柄中區分出管道的讀、寫句柄,就必須将子程序的特殊句柄設定為管道的讀寫句柄。