CreatePipe 回傳讀取句柄 (hReadPipe) 與寫入句柄 (hWritePipe)。BOOL CreatePipe(
PHANDLE hReadPipe, // 輸出:讀取句柄
PHANDLE hWritePipe, // 輸出:寫入句柄
LPSECURITY_ATTRIBUTES lpPipeAttributes, // 安全屬性 (決定可否繼承)
DWORD nSize // 緩衝區大小建議值 (0 = 預設)
);
SECURITY_ATTRIBUTES.bInheritHandle = TRUE → 建立的管道句柄可被子進程繼承。CreateProcess 參數 bInheritHandles = TRUE → 子進程繼承所有可繼承句柄。DuplicateHandle 建立可/不可繼承的副本。父進程透過 SetStdHandle 將管道句柄指派給子進程的標準輸入/輸出/錯誤:
SetStdHandle(STD_INPUT_HANDLE, hRead),子 GetStdHandle(STD_INPUT_HANDLE) → ReadFile。SetStdHandle(STD_OUTPUT_HANDLE, hWrite),父 ReadFile(hRead, ...)。STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
CHAR ReadBuf[1024];
DWORD ReadNum;
HANDLE hRead, hWrite;
// 1. 建立管道 (允許句柄繼承)
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
BOOL bRet = CreatePipe(&hRead, &hWrite, &sa, 0);
if (!bRet) { printf("建立管道失敗: %d\n", GetLastError()); return; }
printf("管道建立成功。\n");
// 2. 保存原標準輸出,將管道寫入端設為子進程標準輸出
HANDLE hOldOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, hWrite);
// 3. 取得啟動資訊並建立子進程
GetStartupInfo(&si);
bRet = CreateProcess(
NULL, _T("Client.exe"), NULL, NULL,
TRUE, // 繼承句柄
0, NULL, NULL, &si, &pi);
SetStdHandle(STD_OUTPUT_HANDLE, hOldOut); // 還原父進程標準輸出
if (!bRet) { printf("建立子進程失敗: %d\n", GetLastError()); return; }
printf("子進程啟動成功 (PID=%d)。\n", pi.dwProcessId);
// 4. 關閉父進程不需要的寫入端 (關鍵!否則 ReadFile 不會遇到 EOF)
CloseHandle(hWrite);
// 5. 讀取管道資料直到 EOF
while (ReadFile(hRead, ReadBuf, sizeof(ReadBuf)-1, &ReadNum, NULL))
{
if (ReadNum == 0) break;
ReadBuf[ReadNum] = '\0';
printf("收到子進程資料: %s", ReadBuf);
}
CloseHandle(hRead);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf("通訊結束。\n");
int main()
{
// 子進程繼承了父進程設定的標準輸出 (管道寫入端)
// 直接用 printf / cout 輸出即自動寫入管道
printf("子進程啟動,PID=%d\n", GetCurrentProcessId());
for (int i = 1; i <= 5; i++)
{
printf("訊息 #%d 來自子進程\n", i);
Sleep(500);
}
printf("子進程結束。\n");
return 0; // 進程結束自動關閉標準輸出句柄,父進程 ReadFile 返回 0 (EOF)
}
| 關鍵步驟 | 說明 |
|---|---|
| CreatePipe + bInheritHandle=TRUE | 建立可繼承的管道句柄對 |
| SetStdHandle(STD_OUTPUT_HANDLE, hWrite) | 將管道寫入端綁定為子進程標準輸出 |
| CreateProcess(..., TRUE, ...) | 啟用句柄繼承建立子進程 |
| 父進程 CloseHandle(hWrite) | 必須關閉寫入端,否則父進程 ReadFile 永不遇到 EOF |
| ReadFile 迴圈 | 讀取直到返回 FALSE 或 ReadNum=0 (EOF) |
CreateNamedPipe) 支援雙向、跨進程、跨網路。FILE_FLAG_OVERLAPPED。CreateFileMapping) + 事件同步。匿名管道是最簡單的父子進程通訊機制,掌握句柄繼承與標準 I/O 重導向,即可快速實現進程間資料傳遞。