2007-07-12 20:06:20 +0900 (546d); rev 2
UNIX に慣れていると、fork のない Windows では どうやってパイプをつないでいるのか疑問に感じる。 ので調べてみた。
まず、Windows に fork はないが、子プロセスを作ることはできる。 この場合、新しく実行ファイルを指定してプロセスを作るわけだ。 (子)プロセスを生成するには ?CreateProcess を使う。
?CreateProcess ではファイルハンドル (ファイルディスクリプタのようなもの) を継承するかどうかを引数で指定する。 この引数を使ってファイルハンドルを継承させれば、 パイプを受け渡すことができる。
また、パイプ(無名パイプ)を作るには CreatePipe を使う。
Ruby では rb_w32_pipe_exec (win32/win32.c) でパイプをつないでいるので、 そのコードを見てみよう。
SECURITY_ATTRIBUTES sa;
// 中略
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // ファイルハンドルを継承。このフラグが最終的にCreateProcessに渡される。
ret = -1;
// 中略
else if (reading) {
if (!CreatePipe(&hIn, &hOut, &sa, 2048L)) { // パイプ作る
errno = map_errno(GetLastError());
break;
}
// 中略
/* create child process */
child = CreateChild(cmd, prog, &sa, hIn, hOut, NULL); // 子プロセス作る
if (!child) {
CloseHandle(hOrg);
CloseHandle(hDupFile);
break;
}
// 以下略
static struct ChildRecord *
CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
HANDLE hInput, HANDLE hOutput, HANDLE hError)
{
// 略
RUBY_CRITICAL({
fRet = CreateProcess(shell, (char *)cmd, psa, psa,
psa->bInheritHandle, dwCreationFlags, NULL, NULL, // 継承しろ!
&aStartupInfo, &aProcessInformation);
errno = map_errno(GetLastError());
});
第五引数 (この場合は SECURITY_ATTRIBUTES 構造体の bInheritHandle メンバー) を TRUE にしておくのが重要。 この引数を TRUE にするとファイルハンドルが継承されて、パイプをつなぐことができる。
なお、パイプを stdout につなぐには、GetStdHandle と SetStdHandle を使う。
see also: http://msdn2.microsoft.com/en-us/library/aa365780.aspx
Related Pages: Win32Api
system revision 1.162