進程間通信 - 匿名管道實現

轉自:http://www.cnblogs.com/BoyXiao/archive/2011/01/01/1923828.html

引子

前面的兩篇博文分別介紹了通過剪貼板和通過郵槽來實現進程之間的通信,

其中剪貼板呢,是用來實現本地兩個進程之間的通信,

而郵槽則既可以實現本地兩個進程之間的通信,也可以實現本地進程和服務器進程的通信,

當然,上面這兩種方式都是有侷限性的,比如剪貼板就只能實現本地進程之間的通信,

而在郵槽中,雖然是既可以實現本地進程之間的通信,又能實現本地進程和遠程服務器進程的通信,

但是使用郵槽的話,服務端只能接收數據,不能發送數據,而客戶端只能發送數據而不能接收數據。

而本篇博文介紹的這個通過匿名管道來實現進程之間的通信的話,

侷限性就顯得更加嚴重了,

第一:匿名管道只能實現本地進程之間的通信,不能實現跨網絡之間的進程間的通信。

第二:匿名管道只能實現父進程和子進程之間的通信,而不能實現任意兩個本地進程之間的通信。

           

            

匿名管道概述

既然是匿名管道的話,自然,就是沒有名字的管道了,還有一種管道呢,叫做命名管道,

命名管道的功能是很強大的,匿名管道在命名管道面前,功能那是簡陋的不行的,

至於命名管道的話,會留到下一篇博文中介紹的,

匿名管道正因爲提供的功能很單一,所以它所需要的系統的開銷也就比命名管道小很多,

在本地機器上可以使用匿名管道來實現父進程和子進程之間的通信,

這裏需要注意兩點,第一就是在本地機器上,這是因爲匿名管道不支持跨網絡之間的兩個進程之間的通信,

第二就是實現的是父進程和子進程之間的通信,而不是任意的兩個進程。

然後得話還順便介紹匿名管道的另外一種功能,其通過匿名管道可以實現子進程輸出的重定向,

何爲輸出重定向呢?還請聽下面詳解:

比如我現在建立一個 Win32 的 Console 程序,然後在其中使用如下代碼來輸出一些信息:

#include <iostream>
using namespace std;
 
int main(int argc, char * argv)
{
    cout<<"Zachary  XiaoZhen "<<endl<<endl;
    cout<<"Happy  New   Year"<<endl<<endl;
    
    system("pause");
}

那麼在默認下,編譯運行上面的代碼時,Windows 會彈出一個黑框框,並且在這個黑框框中顯示一些信息,

image

爲什麼一定要將輸出的信息顯示在這個黑框框中呢?有沒有辦法讓其顯示在我們自己定義的文本框中呢?

而後我們再看一幅截圖:

QQ截圖未命名

上面畫了很多紅線的這個區域中的信息來自那裏呢?爲什麼會在這個文本框中輸出呢?

其實這就可以通過匿名管道來實現,

在卸載 QQ 遊戲這幅截圖中呢,其實運行了兩個進程,

一個就是我們看到的這個輸出了圖形界面的進程,我們稱之爲卸載表象進程(父進程),

而另外一個用來執行真正意義上的卸載的進程我們稱之爲卸載實質進程(子進程)。

其實該卸載表象進程在其執行過程中創建了卸載實質進程來執行真正的卸載操作,

而後,卸載實質進程會輸出上面用紅色矩形標記的區域中的信息,

如果我們使用默認的輸出的話,卸載實質進程會將上面紅色區域標記中的信息輸出到默認的黑框框中,

但是我們可以使用匿名管道來更改卸載實質進程的輸出,

讓其將輸出數據輸入到匿名管道中,而後卸載表象進程從匿名管道中讀取到這些輸出數據,

然後再將這些數據顯示到卸載表象進程的文本框中就可以了。

而上面的這種用來更改卸載實質進程的輸出的技術就稱之爲輸出重定向。

當然與之相對的還有輸入重定向的。

我們可以讓一個進程的輸入來自於匿名管道,而不是我們在黑框框中輸入數據。

話說到這份上呢,也可以點出一點東東了,

上面的這個重定向不就是利用匿名管道實現的父進程和子進程之間的通信嘛。

             

          

匿名管道的使用

匿名管道主要用於本地父進程和子進程之間的通信,

在父進程中的話,首先是要創建一個匿名管道,

在創建匿名管道成功後,可以獲取到對這個匿名管道的讀寫句柄,

然後父進程就可以向這個匿名管道中寫入數據和讀取數據了,

但是如果要實現的是父子進程通信的話,那麼還必須在父進程中創建一個子進程,

同時,這個子進程必須能夠繼承和使用父進程的一些公開的句柄,

爲什麼呢?

因爲在子進程中必須要使用父進程創建的匿名管道的讀寫句柄,

通過這個匿名管道才能實現父子進程的通信,所以必須繼承父進程的公開句柄。

同時在創建子進程的時候,

必須將子進程的標準輸入句柄設置爲父進程中創建匿名管道時得到的讀管道句柄,

將子進程的標準輸出句柄設置爲父進程中創建匿名管道時得到的寫管道句柄。

然後在子進程就可以讀寫匿名管道了。

               

             

匿名管道的創建

BOOL WINAPI CreatePipe(
          __out   PHANDLE hReadPipe,
          __out   PHANDLE hWritePipe,
          __in    LPSECURITY_ATTRIBUTES lpPipeAttributes,
          __in    DWORD nSize );

參數 hReadPipe 爲輸出參數,該句柄代表管道的讀取句柄。

參數 hWritePipe 爲輸出參數,該句柄代表管道的寫入句柄。

參數 lpPipeAttributes 爲一個輸入參數,指向一個 SECURITY_ATTRIBUTES 的結構體指針,

其檢測返回的句柄是否能夠被子進程繼承,如果此參數爲 NULL ,則表明句柄不能被繼承,

在匿名管道中,由於匿名管道要在父子進程之間進行通信,

而子進程如果想要獲得匿名管道的讀寫句柄,則其只能通過從父進程繼承獲得,

當一個子進程從其父進程處繼承了匿名管道的讀寫句柄以後,

子進程和父進程之間就可以通過這個匿名管道的讀寫句柄進行通信了。

所以在這裏必須構建一個 SECURITY_ATTRIBUTES 的結構體,

並且該結構體的第三個結構成員變量 bInheritHandle 參數必須設置爲 TRUE 

從而讓子進程可以繼承父進程所創建的匿名管道的讀寫句柄。

typedef struct _SECURITY_ATTRIBUTES {
 
    DWORD nLength;
 
    LPVOID lpSecurityDescriptor;
 
    BOOL bInheritHandle;
 
} SECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

參數 nSize 用來指定緩衝區的大小,

如果此參數設置爲 ,則表明系統將使用默認的緩衝區大小。一般將該參數設置爲 即可。

         

              

子進程的創建

BOOL  CreateProcess( 
        LPCWSTR pszImageName,  LPCWSTR pszCmdLine, 
        LPSECURITY_ATTRIBUTES psaProcess, 
        LPSECURITY_ATTRIBUTES psaThread, 
        BOOL fInheritHandles,  DWORD fdwCreate, 
        LPVOID pvEnvironment,  LPWSTR pszCurDir, 
        LPSTARTUPINFOW psiStartInfo, 
        LPPROCESS_INFORMATION pProcInfo );

參數 pszImageName 是一個指向 NULL 終止的字符串,用來指定可執行程序的名稱。

參數 pszCmdLine 用來指定傳遞給新進程的命令行字符串,一般做法是在 pszImageName 中傳遞可執行文件的名稱,

在 pszCmdLine 中傳遞命令行參數。

參數 psaProcess 即代表當 CreateProcess 函數創建進程時,需要給進程對象設置一個安全性。

參數 psaThread 代表當 CreateProcess 函數創建新進程後,需要給該進程的主線程對象設置一個安全性。

參數 fInheritHandles 用來指定父進程隨後創建的子進程是否能夠繼承父進程的對象句柄,

如果該參數設置爲 TRUE ,則父進程的每一個可繼承的打開句柄都將被子進程所繼承,

繼承的句柄與原始的句柄擁有同樣的訪問權。

在匿名管道的使用中,因爲子進程需要使用父進程中創建的匿名管道的讀寫句柄,

所以應該將這個參數設置爲 TRUE ,從而可以讓子進程繼承父進程創建的匿名管道的讀寫句柄。

參數 fdwCreate 用來指定控件優先級類和進程創建的附加標記。

如果只是爲了啓動子進程,則並不需要設置它創建的標記,可以將此參數設置爲 0

對於這個參數的具體取值列表可以參考 MSDN 。

參數 pvEnvironment 代表指向環境塊的指針,

如果該參數設置爲 NULL ,則默認將使用父進程的環境。通常給該參數傳遞 NULL

參數 pszCurDir 用來指定子進程當前的路徑,

這個字符串必須是一個完整的路徑名,其包括驅動器的標識符,

如果此參數設置爲 NULL ,那麼新的子進程將與父進程擁有相同的驅動器和目錄。

參數 psiStartInfo 指向一個 StartUpInfo 的結構體的指針,用來指定新進程的主窗口如何顯示。

typedef struct _STARTUPINFOA {
 
    DWORD cb;
 
    LPSTR lpReserved;
 
    LPSTR lpDesktop;
 
    LPSTR lpTitle;
 
    DWORD dwX;
 
    DWORD dwY;
 
    DWORD dwXSize;
 
    DWORD dwYSize;
 
    DWORD dwXCountChars;
 
    DWORD dwYCountChars;
 
    DWORD dwFillAttribute;
 
    DWORD dwFlags;
 
    WORD wShowWindow;
 
    WORD cbReserved2;
 
    LPBYTE lpReserved2;
 
    HANDLE hStdInput;
 
    HANDLE hStdOutput;
 
    HANDLE hStdError;
 
} STARTUPINFOA, *LPSTARTUPINFOA;

對於 dwFlags 參數來說,如果其設置爲 STARTF_USESTDHANDLES 

則將會使用該 STARTUPINFO 結構體中的 hStdInput , hStdOutput , hStdError 成員,

來設置新創建的進程的標準輸入,標準輸出,標準錯誤句柄。

參數 pProcInfo 爲一個輸出參數,

指向一個 PROCESS_INFORMATION 結構體的指針,用來接收關於新進程的標識信息。

typedef struct _PROCESS_INFORMATION 
{             
    HANDLE hProcess;             
    HANDLE hThread;             
    DWORD dwProcessId;              
    DWORD dwThreadId; 
 
}PROCESS_INFORMATION;

其中 hProcess 和 hThread 分別用來標識新創建的進程句柄和新創建的進程的主線程句柄。

dwProcessId 和 dwThreadId 分別是全局進程標識符和全局線程標識符。

前者可以用來標識一個進程,後者用來標識一個線程。

        

               

示例:匿名管道實現父子進程間通信

父進程實現:(簡單 MFC 程序)

項目結構:

image

消息以及成員函數和成員變量的聲明:

public:
    //創建匿名管道
    afx_msg void OnBnClickedBtnCreatePipe();
    //寫匿名管道
    afx_msg void OnBnClickedBtnWritePipe();
    //讀匿名管道
    afx_msg void OnBnClickedBtnReadPipe();
 
    //定義父進程讀匿名管道的成員函數
    void ParentReadPipe(void);
    //定義父進程寫匿名管道的成員函數
    void ParentWritePipe(void);
    //創建 SECURITY_ATTRIBUTES 結構的成員函數
    void CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa);
    //創建 STARTUPINFO 結構的成員函數
    void CreateStartUpInfo(LPSTARTUPINFO lpStartUpInfo);
    //創建匿名管道的成員函數
    void CreateNoNamedPipe(void);
 
    //分別代表要從匿名管道中讀的數據和要寫到匿名管道中的數據
    CString m_CStrReadPipe;
    CString m_CStrWritePipe;
 
    //保存創建匿名管道後所得到的對匿名管道的讀寫句柄
    HANDLE hPipeRead;
    HANDLE hPipeWrite;
    
    //保證匿名管道只創建一次
    BOOL m_PipeIsCreated;

消息映射表定義:

const int        dataLength    = 100;
 
CNoNamedPipeParentDlg::CNoNamedPipeParentDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CNoNamedPipeParentDlg::IDD, pParent)
    , m_CStrReadPipe(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 
    m_PipeIsCreated = FALSE;
}
 
void CNoNamedPipeParentDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT_WRITE_PIPE, m_CStrWritePipe);
    DDX_Text(pDX, IDC_EDIT_READ_PIPE, m_CStrReadPipe);
}
 
BEGIN_MESSAGE_MAP(CNoNamedPipeParentDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_CREATE_PIPE, 
                &CNoNamedPipeParentDlg::OnBnClickedBtnCreatePipe)
    ON_BN_CLICKED(IDC_BTN_WRITE_PIPE, 
                &CNoNamedPipeParentDlg::OnBnClickedBtnWritePipe)
    ON_BN_CLICKED(IDC_BTN_READ_PIPE, 
                &CNoNamedPipeParentDlg::OnBnClickedBtnReadPipe)
END_MESSAGE_MAP()

消息處理函數:

//創建匿名管道按鈕的消息處理函數
void CNoNamedPipeParentDlg::OnBnClickedBtnCreatePipe()
{
    if(m_PipeIsCreated == FALSE)
    {
        this->CreateNoNamedPipe();
    }
}
 
 
//寫入數據到匿名管道中按鈕的消息處理函數
void CNoNamedPipeParentDlg::OnBnClickedBtnWritePipe()
{
    this->ParentWritePipe();
}
 
 
//從匿名管道中讀取數據按鈕的消息處理函數
void CNoNamedPipeParentDlg::OnBnClickedBtnReadPipe()
{
    this->ParentReadPipe();
}
 
 
//接收數據
void CNoNamedPipeParentDlg::ParentReadPipe(void)
{
    DWORD            dwRead;
    char *            pReadBuf;
    CString            cStrRecvData;
 
    pReadBuf = new char[dataLength];
    memset(pReadBuf, 0, dataLength);
 
    if(!ReadFile(hPipeRead, pReadBuf, dataLength, &dwRead, NULL))
    {
        MessageBox(TEXT("   從匿名管道接收數據失敗 ..."), 
            TEXT("提示"), MB_ICONERROR);
        return;
    }
 
    cStrRecvData = "   從匿名管道接收數據成功:    ";
    cStrRecvData += pReadBuf;
 
    this->m_CStrReadPipe.Empty();
 
    this->m_CStrReadPipe = pReadBuf;
    UpdateData(FALSE);
 
    MessageBox(cStrRecvData, TEXT("提示"), MB_ICONINFORMATION);
}
 
 
//發送數據
void CNoNamedPipeParentDlg::ParentWritePipe(void)
{
    UpdateData();
 
    if(!this->m_CStrWritePipe.IsEmpty())
    {
        char *            pSendData;
        DWORD            dwWrite;
        CString            cStrSendData;
 
        //在這裏需要將 Unicode 字符集轉換爲 ASCII 字符集
        pSendData = new char[this->m_CStrWritePipe.GetLength() + 1];
        memset(pSendData, 0, this->m_CStrWritePipe.GetLength() + 1);
        for(int i=0;i<this->m_CStrWritePipe.GetLength();i++)
        {
            pSendData[i] = (char)this->m_CStrWritePipe.GetAt(i);
        }
 
        if(!WriteFile(hPipeWrite, pSendData, 
            this->m_CStrWritePipe.GetLength() + 1, &dwWrite, NULL))
        {
            MessageBox(TEXT("   給匿名管道發送數據失敗 ..."), 
                TEXT("提示"), MB_ICONERROR);
            return;
        }
 
        cStrSendData = "   給匿名管道發送數據成功:    ";
        cStrSendData += this->m_CStrWritePipe;
 
        this->m_CStrWritePipe.Empty();
        UpdateData(FALSE);
 
        MessageBox(cStrSendData, TEXT("提示"), MB_ICONINFORMATION);
    }
    else
    {
        MessageBox(TEXT("   請先輸入要發送給匿名管道的數據 ..."), 
            TEXT("提示"), MB_ICONERROR);
    }
}
 
 
//創建 SECURITY_ATTRIBUTES 結構
void CNoNamedPipeParentDlg::CreateSecurityAttributes(PSECURITY_ATTRIBUTES pSa)
{
    //這裏必須將 bInheritHandle 設置爲 TRUE,
    //從而使得子進程可以繼承父進程創建的匿名管道的句柄
    pSa->bInheritHandle = TRUE;
    pSa->lpSecurityDescriptor = NULL;
    pSa->nLength = sizeof(SECURITY_ATTRIBUTES);
}
 
 
//用來初始化新進程的 STARTUPINFO 成員
void CNoNamedPipeParentDlg::CreateStartUpInfo(LPSTARTUPINFO lpStartUpInfo)
{
    memset(lpStartUpInfo, 0, sizeof(STARTUPINFO));
 
    lpStartUpInfo->cb = sizeof(STARTUPINFO);
    lpStartUpInfo->dwFlags = STARTF_USESTDHANDLES;
 
    //子進程的標準輸入句柄爲父進程管道的讀數據句柄
    lpStartUpInfo->hStdInput = hPipeRead;
 
    //子進程的標準輸出句柄爲父進程管道的寫數據句柄
    lpStartUpInfo->hStdOutput = hPipeWrite;
 
    //子進程的標準錯誤處理句柄和父進程的標準錯誤處理句柄一致
    lpStartUpInfo->hStdError = GetStdHandle(STD_ERROR_HANDLE);
}
 
 
//創建匿名管道
void CNoNamedPipeParentDlg::CreateNoNamedPipe(void)
{
    SECURITY_ATTRIBUTES                sa;
    PROCESS_INFORMATION                processInfo;
    STARTUPINFO                        startUpInfo;
 
    CreateSecurityAttributes(&sa);
    if(!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0))
    {
        MessageBox(TEXT("   創建匿名管道失敗 ..."), 
            TEXT("提示"), MB_ICONERROR);
        return;
    }
 
    CreateStartUpInfo(&startUpInfo);
    if(!CreateProcess(TEXT("NoNamedPipeChild.exe"), 
        NULL, NULL, NULL, TRUE, 
        CREATE_NEW_CONSOLE, NULL, NULL, 
        &startUpInfo, &processInfo))
    {
        CloseHandle(hPipeRead);
        CloseHandle(hPipeWrite);
 
        hPipeWrite = NULL;
        hPipeRead = NULL;
 
        MessageBox(TEXT("   創建子進程失敗 ..."), 
            TEXT("提示"), MB_ICONERROR);
        return;
    }
    else
    {
        m_PipeIsCreated = TRUE;
 
        //對於 processInfo.hProcess 和 processInfo.hThread 
        //這兩個句柄不需要使用,所以釋放資源
        CloseHandle(processInfo.hProcess);
        CloseHandle(processInfo.hThread);
    }
}

子進程實現:(簡單 MFC 程序)

項目結構:

image

消息以及成員函數和成員變量的聲明:

// 實現
protected:
    HICON m_hIcon;
 
    // 生成的消息映射函數
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedBtnWritePipe();
    afx_msg void OnBnClickedBtnReadPipe();
 
    //保存從父進程得到針對於匿名管道的讀寫句柄
    HANDLE hPipeRead;
    HANDLE hPipeWrite;
 
    //分別代表要從匿名管道中讀的數據和要寫到匿名管道中的數據
    CString m_CStrWritePipe;
    CString m_CStrReadPipe;
 
    //子進程讀取匿名管道
    void ChildReadPipe(void);
    //子進程寫匿名管道
    void ChildWritePipe(void);
    //子進程獲取從父進程處繼承得到的關於匿名管道的讀寫句柄
    void GetReadWriteHandleFromParent(void);
 
    //只需要獲取一次匿名管道的讀寫句柄即可
    BOOL m_IsGettedParentHandle;

消息映射表定義:

const int        dataLength    = 100;
 
CNoNamedPipeChildDlg::CNoNamedPipeChildDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CNoNamedPipeChildDlg::IDD, pParent)
    , m_CStrWritePipe(_T(""))
    , m_CStrReadPipe(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 
    this->m_IsGettedParentHandle = FALSE;
}
 
void CNoNamedPipeChildDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDIT_WRITE_PIPE, m_CStrWritePipe);
    DDX_Text(pDX, IDC_EDIT_READ_PIPE, m_CStrReadPipe);
}
 
BEGIN_MESSAGE_MAP(CNoNamedPipeChildDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(ID_BTN_WRITE_PIPE, 
            &CNoNamedPipeChildDlg::OnBnClickedBtnWritePipe)
    ON_BN_CLICKED(ID_BTN_READ_PIPE, 
            &CNoNamedPipeChildDlg::OnBnClickedBtnReadPipe)
END_MESSAGE_MAP()

消息處理函數:

//往匿名管道中寫入數據按鈕的消息處理函數
void CNoNamedPipeChildDlg::OnBnClickedBtnWritePipe()
{
    //如果子進程還沒有獲得對匿名管道的讀寫句柄的話需要先獲取句柄
    this->GetReadWriteHandleFromParent();
 
    ChildWritePipe();
}
 
 
//從匿名管道中讀取數據按鈕的消息處理函數
void CNoNamedPipeChildDlg::OnBnClickedBtnReadPipe()
{
    //如果子進程還沒有獲得對匿名管道的讀寫句柄的話需要先獲取句柄
    this->GetReadWriteHandleFromParent();
 
    ChildReadPipe();
}
 
//從匿名管道讀取數據成員函數
void CNoNamedPipeChildDlg::ChildReadPipe(void)
{
    DWORD            dwRead;
    char *            pReadBuf;
    CString            cStrRecvData;
 
    pReadBuf = new char[dataLength];
    memset(pReadBuf, 0, dataLength);
 
    //讀取數據
    if(!ReadFile(hPipeRead, pReadBuf, dataLength, &dwRead, NULL))
    {
        MessageBox(TEXT("   從匿名管道接收數據失敗 ..."), 
            TEXT("提示"), MB_ICONERROR);
        return;
    }
 
    cStrRecvData = "   從匿名管道接收數據成功:    ";
    cStrRecvData += pReadBuf;
 
    this->m_CStrReadPipe.Empty();
    this->m_CStrReadPipe = pReadBuf;
    UpdateData(FALSE);
 
    MessageBox(cStrRecvData, TEXT("提示"), MB_ICONINFORMATION);
}
 
//往匿名管道中寫入數據
void CNoNamedPipeChildDlg::ChildWritePipe(void)
{
    UpdateData();
 
    if(!this->m_CStrWritePipe.IsEmpty())
    {
        char *                pSendData;
        DWORD                dwWrite;
        CString                cStrSendData;
 
        //在這裏需要將 Unicode 字符集轉換爲 ASCII 字符集
        pSendData = new char[this->m_CStrWritePipe.GetLength() + 1];
        memset(pSendData, 0, this->m_CStrWritePipe.GetLength() + 1);
        for(int i=0;i<this->m_CStrWritePipe.GetLength();i++)
        {
            pSendData[i] = (char)this->m_CStrWritePipe.GetAt(i);
        }
 
        //寫入數據
        if(!WriteFile(hPipeWrite, pSendData, 
            this->m_CStrWritePipe.GetLength(), &dwWrite, NULL))
        {
            MessageBox(TEXT("   給匿名管道發送數據失敗 ..."), 
                TEXT("提示"), MB_ICONERROR);
            return;
        }
 
        cStrSendData = "給匿名管道發送數據成功:    ";
        cStrSendData += this->m_CStrWritePipe;
 
        this->m_CStrWritePipe.Empty();
        UpdateData(FALSE);
 
        MessageBox(cStrSendData, TEXT("提示"), MB_ICONINFORMATION);
    }
    else
    {
        MessageBox(TEXT("   請先輸入要發送給匿名管道的數據 ..."), 
            TEXT("提示"), MB_ICONERROR);
    }
}
 
//需要獲取繼承自父進程的匿名管道讀寫句柄
void CNoNamedPipeChildDlg::GetReadWriteHandleFromParent(void)
{
    if(this->m_IsGettedParentHandle == FALSE)
    {
        hPipeRead = GetStdHandle(STD_INPUT_HANDLE);
        hPipeWrite = GetStdHandle(STD_OUTPUT_HANDLE);
 
        this->m_IsGettedParentHandle = TRUE;
    }
}

效果展示:

首先需要將子進程的可執行文件拷貝到父進程所在目錄下,否則創建進程時會找不到子進程的可執行文件。 

image

啓動父進程可執行文件,並單擊創建匿名管道按鈕,此時會彈出子進程窗口(新建了進程):

image

再在父進程的左邊文本框中輸入數據,單擊寫入數據按鈕:

image

再在子進程窗口中單擊讀取數據按鈕:

image

再在子進程窗口左邊的文本框中輸入數據,單擊寫入數據按鈕:

image

再在父進程窗口中單擊讀取數據按鈕:

image

             

                  

結束語

從上面的效果展示中就可以看出我們確實是實現了父子進程之間通過匿名管道來進行通信,

最後再來總結一下對於匿名管道的使用,

匿名管道一般用於實現本地父子進程之間的通信,其不能實現跨網絡進程之間的通信,

同時其也一般只用於實現父進程和子進程之間的通信。

像匿名管道的話,其和郵槽不同,

其可以實現父進程即可以向子進程發送數據,同時父進程又可以從子進程接收到數據。

而且子進程可以接收來自父進程的數據,並且也可以給父進程發送數據。

最後的話,那就是今天是 2011  年的第一天,說實話,太冷了,實在不想寫博客的,

不過因爲想寫完這個進程之間通信的幾篇博客,同時也對 2011 有個好的開始,

所以硬着頭皮寫下了這篇博客,在這裏希望自己 2011 會更好,人會更成熟,更上進 !!!

同時也祝各位新年快樂,2011 會更好 !!!

    


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章