C++ 進程和匿名管道使用學習

平臺

Windows10 + VS2015ios

學習內容

  • 進程的建立使用(CreateProcess方式)
  • 父子進程間匿名管道通訊

相關函數及參數介紹

  • CreatePipe函數:該的原型爲
CreatePipe(_Out_ PHANDLE hReadPipe,
           _Out_ PHANDLE hWritePipe,
           _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
           _In_ DWORD nSize);

hReadPipe:返回一個可用於讀管道數據的文件句柄;hWritePipe:返回一個可用於寫管道數據的文件句柄;lpPipeAttributes:傳入一個SECURITY_ATTRIBUTES結構的指針,該結構用於決定該函數返回的句柄是否可被子進程繼承;nSize:管道的緩衝區大小,可是這僅僅只是一個理想值,系統根據這個值建立大小相近的緩衝區。若是傳入0 ,那麼系統將使用一個默認的緩衝區大小。須要注意讀寫管道數據的句柄參數位置windows

  • LPSECURITY_ATTRIBUTES類型:相關定義內容爲
typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

nLength:結構體的大小,可用sizeof取得;lpSecurityDescriptor:安全描述符;bInheritHandle:安全描述的對象可否被新建立的進程繼承。緩存

  • CreateProcess函數:WIN32API函數CreateProcess用來建立一個新的進程和它的主線程,這個新進程運行指定的可執行文件。該函數原型有兩種可能,當前環境已定義UNICODE,只參考CreateProcessW
#ifdef UNICODE
#define CreateProcess  CreateProcessW
#else
#define CreateProcess  CreateProcessA
#endif // !UNICODE

WINBASEAPI
BOOL
WINAPI
CreateProcessW(
    _In_opt_ LPCWSTR lpApplicationName,
    _Inout_opt_ LPWSTR lpCommandLine,
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCWSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOW lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation
    );

lpApplicationName:指向一個NULL結尾的、用來指定可執行模塊的字符串,這個參數能夠被設爲NULL,在這種狀況下,可執行模塊的名字必須處於 lpCommandLine 參數最前面並由空格符與後面的字符分開;lpCommandLine:指向一個以NULL結尾的字符串,該字符串指定要執行的命令行,這個參數能夠爲空,那麼函數將使用lpApplicationName參數指定的字符串當作要運行的程序的命令行;lpProcessAttributes:指向一個SECURITY_ATTRIBUTES結構體,這個結構體決定是否返回的句柄能夠被子進程繼承;lpThreadAttributes:同lpProcessAttribute,不過這個參數決定的是線程是否被繼承.一般置爲NULL;bInheritHandles:指示新進程是否從調用進程處繼承了句柄,若是參數的值爲真,調用進程中的每個可繼承的打開句柄都將被子進程繼承,被繼承的句柄與原進程擁有徹底相同的值和訪問權限;dwCreationFlags:指定附加的、用來控制優先類和進程的建立的標誌;lpEnvironment:指向一個新進程的環境塊,若是此參數爲空,新進程使用調用進程的環境;lpCurrentDirectory:指向一個以NULL結尾的字符串,這個字符串用來指定子進程的工做路徑,這個字符串必須是一個包含驅動器名的絕對路徑;lpStartupInfo指向一個用於決定新進程的主窗體如何顯示的STARTUPINFO結構體;lpProcessInformation:指向一個用來接收新進程的識別信息的PROCESS_INFORMATION結構體。安全

  • dwCreationFlags參數:dwCreationFlags可選類型列表以下
參數值 描述
CREATE_DEFAULT_ERROR_MODE 新的進程不繼承調用進程的錯誤模式
CREATE_NEW_CONSOLE 新的進程將使用一個新的控制檯,而不是繼承父進程的控制檯。這個標誌不能與DETACHED_PROCESS標誌一塊兒使用
CREATE_NEW_PROCESS_GROUP 新進程將是一個進程樹的根進程
CREATE_SEPARATE_WOW_VDM 若是被設置,新進程將會在一個私有的虛擬DOS機(VDM)中運行
CREATE_SHARED_WOW_VDM 若是WIN.INI中的Windows段的DefaultSeparateVDM選項被設置爲真,這個標識使得CreateProcess函數越過這個選項並在共享的虛擬DOS機中運行新進程
CREATE_SUSPENDED 新進程的主線程會以暫停的狀態被建立,直到調用ResumeThread函數被調用時才運行
CREATE_UNICODE_ENVIRONMENT 若是被設置,由lpEnvironment參數指定的環境塊使用Unicode字符,若是爲空,環境塊使用ANSI字符
DEBUG_PROCESS 若是這個標誌被設置,調用進程將被當作一個調試程序,而且新進程會被當作被調試的進程。系統把被調試程序發生的全部調試事件通知給調試器,若是使用這個標誌建立進程,只有調用進程(調用CreateProcess函數的進程)能夠調用WaitForDebugEvent函數
DEBUG_ONLY_THIS_PROCESS 若是此標誌沒有被設置且調用進程正在被調試,新進程將成爲調試調用進程的調試器的另外一個調試對象。若是調用進程沒有被調試,有關調試的行爲就不會產生
DETACHED_PROCESS 對於控制檯進程,新進程沒有訪問父進程控制檯的權限。新進程能夠經過AllocConsole函數本身建立一個新的控制檯。這個標誌不能夠與CREATE_NEW_CONSOLE標誌一塊兒使用
CREATE_NO_WINDOW 系統不爲新進程建立CUI窗口,使用該標誌能夠建立不含窗口的CUI程序
HIGH_PRIORITY_CLASS 指示這個進程將執行時間臨界的任務,因此它必須被當即運行以保證正確。這個優先級的程序優先於正常優先級或空閒優先級的程序
IDLE_PRIORITY_CLASS 指示這個進程的線程只有在系統空閒時纔會運行而且能夠被任何高優先級的任務打斷
NORMAL_PRIORITY_CLASS 指示這個進程沒有特殊的任務調度要求
REALTIME_PRIORITY_CLASS 指示這個進程擁有可用的最高優先級。一個擁有實時優先級的進程的線程能夠打斷全部其餘進程線程的執行,包括正在執行重要任務的系統進程
  • STARTUPINFO參數:該參數原型有兩種可能,當前環境已定義UNICODE,只參考STARTUPINFOW
#ifdef UNICODE
typedef STARTUPINFOW STARTUPINFO;
typedef LPSTARTUPINFOW LPSTARTUPINFO;
#else
typedef STARTUPINFOA STARTUPINFO;
typedef LPSTARTUPINFOA LPSTARTUPINFO;
#endif // UNICODE

typedef struct _STARTUPINFOW {
    DWORD   cb;
    LPWSTR  lpReserved;
    LPWSTR  lpDesktop;
    LPWSTR  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;
} STARTUPINFOW, *LPSTARTUPINFOW;

結構體參數內容較多,練習使用時只用到了cb``dwFlags``wShowWindow``hStdInput``hStdOutput``hStdError,具體參數解釋以下表函數

參數 描述
cb 包含STARTUPINFO結構中的字節數,應用程序必須將cb初始化爲sizeof(STARTUPINFO)
lpReserved 保留,必須初始化爲NULL
lpDesktop 用於標識啓動應用程序所在的桌面的名字。若是該桌面存在,新進程便與指定的桌面相關聯。若是桌面不存在,便建立一個帶有默認屬性的桌面,並使用爲新進程指定的名字。若是lpDesktop是NULL(這是最多見的狀況),那麼該進程將與當前桌面相關聯
lpTitle 用於設定控制檯窗口的名稱。若是lpTitle是NULL,則可執行文件的名字將用做窗口名
dwX 用於設定應用程序窗口在屏幕上應該放置的位置的x座標(以像素爲單位)
dwY 用於設定應用程序窗口在屏幕上應該放置的位置的y座標(以像素爲單位),只有當子進程用CW_USEDEFAULT做爲CreateWindow的x參數來建立它的第一個重疊窗口時,才使用這兩個座標。如果建立控制檯窗口的應用程序,這些成員用於指明控制檯窗口的左上角
dwXSize 用於設定應用程序窗口的寬度(以像素爲單位)當子進程將CW_USEDEFAULT用做CreateWindow的nWidth參數來建立它的第一個重疊窗口時,才使用
dwYSize 用於設定應用程序窗口的長度(以像素爲單位)當子進程將CW_USEDEFAULT用做CreateWindow的nWidth參數來建立它的第一個重疊窗口時,才使用
dwXCountChars 用於設定子應用程序的控制檯窗口的寬度(以字符爲單位)
dwYCountChars 用於設定子應用程序的控制檯窗口的高度(以字符爲單位)
dwFillAttribute 用於設定子應用程序的控制檯窗口使用的文本和背景顏色
dwFlags 子進程窗口標誌
wShowWindow 用於設定若是子應用程序初次調用的ShowWindow將SW_SHOWDEFAULT做爲nCmdShow參數傳遞時,該應用程序的第一個重疊窗口應該如何出現
cbReserved2 保留,必須被初始化爲0
lpReserved2 保留,必須被初始化爲NULL
hStdInput 用於設定供控制檯輸入用的緩存的句柄
hStdOutput 用於設定供控制檯輸出用的緩存的句柄
hStdError 用於設定供控制檯輸出用的緩存的句柄
  • dwFlags參數:該參數可選類型以下
參數 描述
STARTF_USESIZE 使用dwXSize和dwYSize成員
STARTF_USESHOWWINDOW 使用wShowWindow成員
STARTF_USEPOSITION 使用dwX和dwY成員
STARTF_USECOUNTCHARS 使用dwXCountChars和dwYCountChars成員
STARTF_USEFILLATTRIBUTE 使用dwFillAttribute成員
STARTF_USESTDHANDLES 使用hStdInput、hStdOutput和hStdError成員
STARTF_RUN_FULLSCREEN 強制在x86計算機上運行的控制檯應用程序以全屏幕方式啓動運行

父進程代碼

1 .父進程的功能是建立管道和建立進程
2 .建立成功後等待控制檯輸入信息並經過管道發送給子進程
3 .等待一段時間後從管道讀取數據
4 .將管道數據輸出到控制檯學習

#include <iostream>
#include <windows.h>
using namespace std;

char rxbuff[100] = { 0 };
char txbuff[100] = { 0 };
DWORD txcount = 0, rxcount = 0;

void main(void)
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    //管道建立
    HANDLE hwrite, hread;
    if (CreatePipe(&hread,&hwrite,&sa,0)==NULL)
    {
        cout << "pPipe Create error!" << endl;
        return;
    }

    //進程建立
    STARTUPINFO si;
    ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOW;
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    si.hStdOutput = hwrite;
    si.hStdInput = hread;

    PROCESS_INFORMATION pi; 
    TCHAR exe[] = TEXT("E:\\Soft_Pro\\VC_work\\MD5_Check\\Debug\\MD5_Check.exe");
    //建立子進程
    if (CreateProcess(NULL,
                      exe,
                      NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)==NULL)
    {
        cout << "進程建立錯誤" << endl;
        CloseHandle(hread);
        CloseHandle(hwrite);
        hread = NULL;
        hwrite = NULL;
        return;
    }
    else
    {
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }

    cin >> txbuff;
    //父進程往管道寫數據
    if (!WriteFile(hwrite, txbuff, sizeof(txbuff), &txcount, NULL))
    {
        cout << "父進程寫數據失敗!" << endl;
        return;
    }
    else
    {
        cout << "父進程寫數據成功!" << endl;
    }

    Sleep(300);

    //父進程從管道讀取數據
    if (!ReadFile(hread,rxbuff,100,&rxcount,NULL))
    {
        cout << "父進程讀取失敗!" << endl;
        return;
    }
    else
    {
        cout << "父進程管道讀取數據:" << rxbuff << endl;
    }

    system("pause");
}

子進程代碼

1 .子進程獲取管道數據的文件句柄
2 .子進程從輸入端讀取管道數據
3 .子進程將讀取的數據從輸出端發送至管道spa

#include <iostream>
#include <windows.h>
using namespace std;

char rxbuff[100] = {0};
char txbuff[100] = {0};
DWORD txcount = 0, rxcount = 0;
HANDLE hRead, hWrite;

int main(void)
{
    hRead = GetStdHandle(STD_INPUT_HANDLE);
    hWrite = GetStdHandle(STD_OUTPUT_HANDLE);

        //讀管道數據
    if (!ReadFile(hRead,rxbuff,100,&rxcount,NULL))
    {
        cout << "子進程讀管道失敗" << endl;
        return 0;
    }
    sprintf_s(txbuff, "子進程應答:%s\n", rxbuff);

    Sleep(200);

        //寫管道數據
    if (!WriteFile(hWrite,txbuff,sizeof(txbuff),&txcount,NULL))
    {
        cout << "子進程寫失敗!" << endl;
        return 0;
    }

    return 0;
}

父進程運行結果

額外說明

  • CreateProcess的lpCommandLine參數使用TEXT("path")方式建立進程時老是報錯,後來在一篇博客裏看到了解決方案
  • 初次學習還有部分問題,後續繼續補充
相關文章
相關標籤/搜索