平臺
Windows10 + VS2015
學習內容
- 行程的創建使用(
CreateProcess方式) - 父子行程間匿名管道通信
相關函式及引數介紹
- CreatePipe函式:該的原型為
CreatePipe(_Out_ PHANDLE hReadPipe,
_Out_ PHANDLE hWritePipe,
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
_In_ DWORD nSize);
hReadPipe:回傳一個可用于讀管道資料的檔案句柄;hWritePipe:回傳一個可用于寫管道資料的檔案句柄;lpPipeAttributes:傳入一個SECURITY_ATTRIBUTES結構的指標,該結構用于決定該函式回傳的句柄是否可被子行程繼承;nSize:管道的緩沖區大小,但是這僅僅只是一個理想值,系統根據這個值創建大小相近的緩沖區,如果傳入0 ,那么系統將使用一個默認的緩沖區大小,需要注意讀寫管道資料的句柄引數位置,
- 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 .子行程將讀取的資料從輸出端發送至管道
#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")方式創建行程時總是報錯,后來在一篇博客里看到了解決方案 - 初次學習還有部分問題,后續繼續補充
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/73346.html
標籤:C++
