_spawn 系関数と _wspawn 系関数
更新 : 2007 年 11 月
_spawn 系関数は、新規プロセスを生成して実行します。
関数名の最後の文字は、関数の種類を示します。
e
環境設定へのポインタ配列 envp が新しいプロセスに渡されます。l
コマンド ライン引数が _spawn 関数に個別に渡されます。このサフィックスは、通常は新規プロセスのパラメータの数が事前にわかっている場合に使用します。p
PATH 環境変数を使用して、実行するファイルを検索します。v
_spawn 関数にコマンド ライン引数へのポインタ配列 argv が渡されます。このサフィックスは、通常は新規プロセスのパラメータの数が変化する場合に使用します。
解説
_spawn 系関数は、それぞれ新規プロセスを生成して実行します。現在使用中のマルチバイト コード ページに従ってマルチバイト文字列を認識し、必要に応じてマルチバイト文字列引数を自動的に処理します。_wspawn 系関数は _spawn 系関数のワイド文字バージョンで、マルチバイト文字列は処理しません。それ以外では、_wspawn 系関数と対応する _spawn 系関数の動作は同じです。
汎用テキスト ルーチンのマップ
Tchar.h のルーチン |
_UNICODE および _MBCS が未定義の場合 |
_MBCS が定義されている場合 |
_UNICODE が定義されている場合 |
---|---|---|---|
_tspawnl |
_spawnl |
_spawnl |
_wspawnl |
_tspawnle |
_spawnle |
_spawnle |
_wspawnle |
_tspawnlp |
_spawnlp |
_spawnlp |
_wspawnlp |
_tspawnlpe |
_spawnlpe |
_spawnlpe |
_wspawnlpe |
_tspawnv |
_spawnv |
_spawnv |
_wspawnv |
_tspawnve |
_spawnve |
_spawnve |
_wspawnve |
_tspawnvp |
_spawnvp |
_spawnvp |
_wspawnvp |
_tspawnvpe |
_spawnvpe |
_spawnvpe |
_wspawnvpe |
新規プロセスを読み込んで実行するための十分なメモリが必要です。mode 引数によって、_spawn の実行前と実行中の呼び出し側プロセスの動作が決まります。Process.h には、以下の mode 値が定義されています。
_P_OVERLAY
呼び出し側プロセスを破棄し、新規プロセスでオーバーレイします。_exec 呼び出しと同じ効果があります。_P_WAIT
新規プロセスの実行が完了するまでスレッドの呼び出しを中断します (同期 _spawn 関数)。_P_NOWAIT または _P_NOWAITO
新規プロセスと共に呼び出し側プロセスの実行を継続します (非同期 _spawn 関数)。_P_DETACH
呼び出し側プロセスの実行を継続します。新規プロセスは、コンソールやキーボードへのアクセスなしにバックグラウンドで実行されます。新規プロセスに対して _cwait を呼び出すと失敗します (非同期 _spawn 関数)。
cmdname 引数には、新規プロセスとして実行するファイルを指定します。ルートからの完全パス、現在の作業ディレクトリからの相対パス、またはファイル名のみで指定できます。cmdname ファイル名拡張子がない場合、またはピリオド (.) で終わっていない場合、_spawn 関数は最初に .com 拡張子、次に .exe と .bat 拡張子、最後に .cmd 拡張子を試します。
cmdname に拡張子がある場合は、その拡張子のファイルのみを使用します。cmdname がピリオドで終わっている場合、_spawn の呼び出しはファイル名拡張子がない cmdname を検索します。_spawnlp、_spawnlpe、_spawnvp、および _spawnvpe の各関数は、PATH 環境変数に指定されたディレクトリ内で同じ手順を使用して cmdname を検索します。
cmdname にドライブ指定子やスラッシュが含まれている場合、つまり相対パスが指定されている場合、_spawn 呼び出しは指定されているファイルだけを検索し、パスは検索しません。
Visual C++ 2005 では、_spawn 系関数は大きく変更されています。これまでは、一部の関数で正常終了時に errno が 0 に設定されましたが、新しい仕様では、errno は C の標準仕様に準拠して正常終了時に変更されません。古い動作をエミュレートする必要がある場合は、これらの関数を呼び出す直前に errno を 0 に設定します。
メモ : |
---|
オーバーレイを正常に初期化、終了するためには、setjmp 関数または longjmp 関数を使用せずオーバーレイ ルーチンに制御を渡します。戻るときも同じです。 |
子プロセス用の引数
新規プロセスに引数を渡すには、_spawn の呼び出しで引数として文字列へのポインタを 1 つ以上指定します。これらの文字列は、子プロセスの引数リストになります。新規プロセスの引数リストを形成する文字列全体の長さは、1024 バイト以内にする必要があります。この長さには、各文字列の終端の NULL 文字 (\0) は含まれませんが、引数を区切るために自動的に挿入されるスペース文字は含まれます。
メモ : |
---|
文字列に空白が含まれる場合、予期しない動作になることがあります。たとえば、_spawn を "hi there" という文字列に渡すと、新しいプロセスは "hi" と "there" という 2 つの引数を使用する結果になります。新しいプロセスでは "hi there" というファイルを開こうとするため、プロセスは失敗します。この問題を回避するには、"\"hi there\"" のように文字列を引用符で囲みます。 |
セキュリティに関するメモ : |
---|
ユーザー入力のコンテンツを明示的にチェックしないまま _spawn に渡さないでください。_spawn によって CreateProcess が呼び出されます。そのため、パス名が修飾されていない場合、セキュリティ上の脆弱性につながる可能性があります。 |
引数のポインタは、個別の引数として (_spawnl、_spawnle、_spawnlp、および _spawnlpe の場合)、またはポインタ配列として (_spawnv、_spawnve、_spawnvp、および _spawnvpe の場合) 渡すことができます。子プロセスには、少なくとも引数 arg0 または argv[0] のいずれかを渡す必要があります。規約では、この引数にはコマンド ラインに入力するプログラム名を指定することになっています。ほかの値を指定してもエラーは発生しません。
通常、_spawnl、_spawnle、_spawnlp、_spawnlpe の各関数は、引数の数が事前にわかっている場合に呼び出します。通常の場合、arg0 引数は cmdname へのポインタです。引数 arg1 ~ argn は、新規の引数リストを形成する文字列へのポインタです。argn の後には、引数リストの終端を示す NULL ポインタが必要です。
_spawnv、_spawnve、_spawnvp、および _spawnvpe の各呼び出しは、新しいプロセスの引数の数が変化する場合に便利です。引数へのポインタは、配列 argv として渡されます。引数 argv[0] は、通常、リアル モードではパスへのポインタ、プロテクト モードではプログラム名へのポインタです。argv[1] ~ argv[n] は、新規の引数リストを形成する文字列へのポインタです。引数 argv[n +1] には、引数リストの終端を示す NULL ポインタを指定する必要があります。
子プロセスの環境
_spawn 関数の呼び出し時に開いていたファイルは、新規プロセスでも開いています。_spawnl、_spawnlp、_spawnv、および _spawnvp の各関数の呼び出しでは、新規プロセスは呼び出し側プロセスの環境を継承します。_spawnle、_spawnlpe、_spawnve、および _spawnvpe の各関数を呼び出すと、引数 envp を通じて環境設定リストを渡すことによって新規プロセスの環境を変更できます。引数 envp は文字ポインタの配列であり、最後の要素以外の各要素は、環境変数を定義する、NULL で終わる文字列を指します。通常、このような文字列の形式は NAME=value であり、NAME は環境変数名、value はその変数に設定する文字列の値です。value は二重引用符で囲みません。envp 配列の最後の要素は NULL にする必要があります。envp 自体が NULL の場合、子プロセスは親プロセスの環境設定を継承します。
_spawn 系関数では、変換モードなど、開いているファイルに関するすべての情報を新規プロセスに渡すことができます。この情報は、環境の C_FILE_INFO エントリを使用してリアル モードで渡されます。通常、スタートアップ コードはこのエントリの処理後に、環境から削除されます。ただし、_spawn 関数で C 以外のプロセスを生成する場合、このエントリは環境に残ります。環境情報はリアル モードではバイナリ形式で渡されるため、環境を出力すると、このエントリの定義文字列にはグラフィックス文字が表示されます。通常の操作には、これ以外の影響はありません。プロテクト モードでは、環境情報はテキスト形式で渡されるため、グラフィックス文字は含まれません。
_spawn 関数を呼び出すには、fflush または _flushall を使用してストリームを明示的にフラッシュするか、閉じる必要があります。
_spawn ルーチンを呼び出して作成した新規プロセスでは、シグナルの設定は保持されません。シグナルの設定は既定値にリセットされます。
出力のリダイレクト
DLL または GUI アプリケーションから _spawn を呼び出し、その出力をパイプにリダイレクトする場合、次の 2 つの選択肢があります。
Win32 API を使用してパイプを作成した後、AllocConsole を呼び出し、そのハンドルの値を startup 構造体に設定して、CreateProcess を呼び出す。
パイプを作成し、cmd.exe /c (または command.exe /c) を使ってアプリケーションを起動する _popen、_wpopen を呼び出す。
使用例
// crt_spawn.c
// This program accepts a number in the range
// 1-8 from the command line. Based on the number it receives,
// it executes one of the eight different procedures that
// spawn the process named child. For some of these procedures,
// the CHILD.EXE file must be in the same directory; for
// others, it only has to be in the same path.
//
#include <stdio.h>
#include <process.h>
char *my_env[] =
{
"THIS=environment will be",
"PASSED=to child.exe by the",
"_SPAWNLE=and",
"_SPAWNLPE=and",
"_SPAWNVE=and",
"_SPAWNVPE=functions",
NULL
};
int main( int argc, char *argv[] )
{
char *args[4];
// Set up parameters to be sent:
args[0] = "child";
args[1] = "spawn??";
args[2] = "two";
args[3] = NULL;
if (argc <= 2)
{
printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
exit( 1 );
}
switch (argv[1][0]) // Based on first letter of argument
{
case '1':
_spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
break;
case '2':
_spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
NULL, my_env );
break;
case '3':
_spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
break;
case '4':
_spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
NULL, my_env );
break;
case '5':
_spawnv( _P_OVERLAY, argv[2], args );
break;
case '6':
_spawnve( _P_OVERLAY, argv[2], args, my_env );
break;
case '7':
_spawnvp( _P_OVERLAY, argv[2], args );
break;
case '8':
_spawnvpe( _P_OVERLAY, argv[2], args, my_env );
break;
default:
printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
exit( 1 );
}
printf( "from SPAWN!\n" );
}
child process output
from SPAWN!