#156 Anonymous Pipes
Windowsには、プロセス間でやりとりをするための仕組みが用意されていて、パイプと呼ばれています。
パイプには、匿名パイプと名前付きパイプの2種類があり、用途に応じて使い分けます。
匿名パイプ
親子関係のあるプロセス間などで使われる、1方向のパイプ
名前付きパイプ
パイプサーバーと複数のパイプクライアントでの通信に使われる1方向または双方向のパイプ
匿名パイプ
匿名パイプを使って、プロセス間通信をしてみたいと思います。
親プロセスから「cmd.exe」の子プロセスを生成して、子プロセスの標準入力・標準出力を親プロセスと連携させます。
コード
#include <Windows.h>
#include <iostream>
void ReadFromPipe(HANDLE StdOutRead)
{
DWORD dwRead, dwWritten;
CHAR chBuf[1024];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
bSuccess = ReadFile(StdOutRead, chBuf, 1024, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
bSuccess = WriteFile(hParentStdOut, chBuf,
dwRead, &dwWritten, NULL);
if (!bSuccess) break;
}
}
void WriteToPipe(HANDLE StdInWrite)
{
DWORD dwRead, dwWritten;
CHAR chBuf[1024];
BOOL bSuccess = FALSE;
HANDLE hParentStdIn = GetStdHandle(STD_INPUT_HANDLE);
for (;;)
{
bSuccess = ReadFile(hParentStdIn, chBuf, 1024, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
bSuccess = WriteFile(StdInWrite, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess) break;
}
if (!CloseHandle(StdInWrite)) {
printf("[!] CloseHandle failed with error: %d\n", GetLastError());
}
}
int main()
{
HANDLE StdInRead = NULL;
HANDLE StdInWrite = NULL;
HANDLE StdOutRead = NULL;
HANDLE StdOutWrite = NULL;
HANDLE hProcess = NULL;
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
SECURITY_ATTRIBUTES sa = { 0 };
wchar_t lpCmd[] = L"cmd.exe";
RtlZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
RtlZeroMemory(&si, sizeof(STARTUPINFO));
RtlZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&StdInRead, &StdInWrite, &sa, 0)) {
printf("[!] CreatePipe(1) failed with error: %d\n", GetLastError());
return FALSE;
}
if (!CreatePipe(&StdOutRead, &StdOutWrite, &sa, 0)) {
printf("[!] CreatePipe(2) failed with error: %d\n", GetLastError());
return FALSE;
}
if (!SetHandleInformation(StdInWrite, HANDLE_FLAG_INHERIT, 0)) {
printf("[!] SetHandleInformation(1) failed with error: %d\n", GetLastError());
return -1;
}
if (!SetHandleInformation(StdOutRead, HANDLE_FLAG_INHERIT, 0)) {
printf("[!] SetHandleInformation(2) failed with error: %d\n", GetLastError());
return -1;
}
si.cb = sizeof(STARTUPINFO);
si.dwFlags |= (STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES);
si.wShowWindow = SW_HIDE;
si.hStdInput = StdInRead;
si.hStdOutput = si.hStdError = StdOutWrite;
if (!CreateProcessW(NULL, lpCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
return -1;
}
hProcess = pi.hProcess;
CloseHandle(StdInRead);
CloseHandle(StdOutWrite);
HANDLE hOutThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ReadFromPipe, StdOutRead, NULL, NULL);
HANDLE hInThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)WriteToPipe, StdInWrite, NULL, NULL);
WaitForMultipleObjects(1, &hOutThread, TRUE, INFINITE);
WaitForMultipleObjects(1, &hInThread, TRUE, INFINITE);
}
Visual Studioでビルドして実行すると、コマンドプロンプトが立ち上がります。コンソールの標準入力・標準出力を子プロセスの「cmd.exe」と接続しているため、普通の「cmd.exe」と同じように扱うことができます。
まあ、これだけではそんなに役に立つものではありませんが…
アイデア次第でおもしろいことができそうです。
EOF