_exec、_wexec 系関数
更新 : 2007 年 11 月
この系列の各関数は、新しいプロセスを読み込んで実行します。
関数名の最後の文字は、関数の種類を示します。
_exec 関数のサフィックス |
説明 |
---|---|
e |
環境設定へのポインタ配列 envp が新しいプロセスに渡されます。 |
l |
コマンド ライン引数が _exec 関数に個別に渡されます。通常は、新しいプロセスに渡すパラメータの個数が事前にわかっている場合に使用します。 |
p |
PATH 環境変数を使用して、実行するファイルを検索します。 |
v |
コマンド ライン引数へのポインタ配列 argv が _exec に渡されます。通常は、新しいプロセスに渡すパラメータの個数に変動がある場合に使用します。 |
解説
各 _exec 関数は、新しいプロセスを読み込んで実行します。_exec 系関数はすべて、同じオペレーティング システム関数を使用します。_exec 系関数は、現在使用中のマルチバイト コード ページに従ってマルチバイト文字シーケンスを認識し、マルチバイト文字列の引数を適切な方法で自動的に処理します。_wexec 系関数は、_exec 系関数のワイド文字バージョンです。_wexec 系関数の処理内容は _exec 系関数とほぼ同様ですが、マルチバイト文字列は処理しません。
汎用テキスト ルーチンのマップ
Tchar.h のルーチン |
_UNICODE および _MBCS が未定義の場合 |
_MBCS が定義されている場合 |
_UNICODE が定義されている場合 |
---|---|---|---|
_texecl |
_execl |
_execl |
_wexecl |
_texecle |
_execle |
_execle |
_wexecle |
_texeclp |
_execlp |
_execlp |
_wexeclp |
_texeclpe |
_execlpe |
_execlpe |
_wexeclpe |
_texecv |
_execv |
_execv |
_wexecv |
_texecve |
_execve |
_execve |
_wexecve |
_texecvp |
_execvp |
_execvp |
_wexecvp |
_texecvpe |
_execvpe |
_execvpe |
_wexecvpe |
_exec 系関数の呼び出しが成功すると、呼び出し側プロセスによって事前に確保されていたメモリに新しいプロセスが配置されます。新しいプロセスの読み込みおよび実行には、十分なメモリ領域が必要です。
パラメータ cmdname には、新しいプロセスとして実行するファイルを指定します。完全パス (ルートからのパス)、相対パス (現在の作業ディレクトリからのパス)、またはファイル名のいずれでも指定できます。cmdname にファイル名の拡張子がない場合、または末尾にピリオド (.) がない場合、_exec 系関数はその名前でファイルを検索します。検索に失敗すると、同じ基本名で拡張子が .com のファイルを検索し、続いて拡張子が .exe、.bat、.cmd のファイルを順に検索します。cmdname に拡張子がある場合は、その拡張子のファイルだけを検索します。cmdname の末尾にピリオドがある場合、_exec 関数はファイル名拡張子がない cmdname を検索します。_execlp、_execlpe、_execvp、および _execvpe は、PATH 環境変数に指定されたディレクトリ内で同じ処理手順を使用して cmdname を検索します。cmdname にドライブ指定子やスラッシュが含まれている場合、つまり相対パスが指定されている場合、_exec 呼び出しは指定のファイルだけを検索し、パスは検索しません。
_exec 呼び出しのパラメータとして文字列へのポインタを指定することにより、新しいプロセスにパラメータが渡されます。これらの文字列が新しいプロセスのパラメータ リストとなります。呼び出しプロセスから継承した環境設定の文字列と、新しいプロセスのパラメータ リストの文字列を合わせた長さが、32 KB を超えないようにしてください。各文字列の終端を表す NULL 文字 ('\0') はカウントされませんが、パラメータを区切るために自動的に挿入されるスペース文字はカウントされます。
メモ : |
---|
文字列に空白が含まれる場合、予期しない動作になることがあります。たとえば、_exec を "hi there" という文字列に渡すと、新しいプロセスは "hi" と "there" という 2 つの引数を使用する結果になります。新しいプロセスでは "hi there" というファイルを開こうとするため、プロセスは失敗します。この問題を回避するには、"\"hi there\"" のように文字列を引用符で囲みます。 |
セキュリティに関するメモ : |
---|
ユーザー入力のコンテンツを明示的にチェックしないまま _exec に渡さないでください。_exec によって CreateProcess が呼び出されます。そのため、パス名が修飾されていない場合、セキュリティ上の脆弱性につながる可能性があります。 |
Visual C++ 2005 では、_exec 関数はパラメータの検証を行います。いずれかのパラメータが null ポインタ、空の文字列、または省略されている場合、「パラメータの検証」に説明されているように、_exec の関数は無効なパラメータ ハンドラを呼び出します。実行の継続が許可された場合、これらの関数は errno を EINVAL に設定し、-1 を返します。新しいプロセスは実行されません。
_execl、_execle、_execlp、および _execlpe では引数へのポインタが個別のパラメータとして渡され、_execv、_execve、_execvp、および _execvpe ではポインタの配列として渡されます。新しいプロセスには、少なくとも 1 つのパラメータ arg0 を渡す必要があり、このパラメータが新しいプロセスの argv[0] となります。通常、このパラメータは cmdname のコピーです。ただし、別の値を使用しても、エラーは発生しません。
_execl、_execle、_execlp、_execlpe の各呼び出しは、通常、パラメータの個数が事前にわかっている場合に使用します。通常の場合、arg0 パラメータは cmdname へのポインタです。パラメータ arg1 ~ argn は、新しいパラメータ リストを構成する文字列を指します。argn の後には、パラメータ リストの終端を示すために NULL ポインタが必要です。
_execv、_execve、_execvp、および _execvpe の各呼び出しは、新しいプロセスのパラメータの数が変化する場合に便利です。パラメータへのポインタは、配列 argv として渡されます。通常の場合、パラメータ argv[0] は cmdname へのポインタです。パラメータ argv[1] ~ argv[n] は、新しいパラメータ リストを構成する文字列を指します。パラメータ リストの終端を示すために、パラメータ argv[n+1] は NULL ポインタである必要があります。
_exec 呼び出しを作成するときに開いたファイルは、新しいプロセスでも開いたままです。_execl、_execlp、_execv、および _execvp の各呼び出しでは、新しいプロセスが呼び出しプロセスの環境を継承します。_execle、_execlpe、_execve、および _execvpe の各呼び出し時に、新しいプロセスにパラメータ envp として環境設定のリストを渡すことによって、新しいプロセスの環境を変更できます。envp は文字ポインタの配列であり、最後の要素を除く各要素は、NULL で終わる環境変数定義の文字列を指します。通常、このような文字列の形式は NAME=value であり、NAME は環境変数名、value はその変数に設定する文字列の値です。value は二重引用符で囲みません。envp 配列の最後の要素は NULL にする必要があります。envp 自身が NULL である場合、新しいプロセスは呼び出しプロセスの環境設定を継承します。
_exec 系関数で実行されるプログラムは、常に、プログラムの .exe ファイル ヘッダーの maximum allocation フィールドが既定値 0xFFFFH であるかのように、メモリに読み込まれます。
_exec 呼び出しは、開いているファイルの変換モードを保持しません。呼び出しプロセスから継承されたファイルを新しいプロセスで使用する必要がある場合は、_setmode ルーチンを使用して、ファイルの変換モードを必要なモードに設定します。_exec 系関数を呼び出す前に、fflush または _flushall を使用してストリームを明示的にフラッシュするか、ストリームを閉じる必要があります。_exec ルーチンの呼び出しによって作成された新しいプロセスでは、呼び出し側のシグナル設定が保持されません。シグナル設定は、新しいプロセスでは既定値にリセットされます。
使用例
// crt_args.c
// Illustrates the following variables used for accessing
// command-line arguments and environment variables:
// argc argv envp
// This program will be executed by crt_exec which follows.
#include <stdio.h>
int main( int argc, // Number of strings in array argv
char *argv[], // Array of command-line argument strings
char **envp ) // Array of environment variable strings
{
int count;
// Display each command-line argument.
printf( "\nCommand-line arguments:\n" );
for( count = 0; count < argc; count++ )
printf( " argv[%d] %s\n", count, argv[count] );
// Display each environment variable.
printf( "\nEnvironment variables:\n" );
while( *envp != NULL )
printf( " %s\n", *(envp++) );
return;
}
次のプログラムを使用して Crt_args.exe を実行します。
// crt_exec.c
// Illustrates the different versions of exec, including
// _execl _execle _execlp _execlpe
// _execv _execve _execvp _execvpe
//
// Although CRT_EXEC.C can exec any program, you can verify how
// different versions handle arguments and environment by
// compiling and specifying the sample program CRT_ARGS.C. See
// "_spawn, _wspawn Functions" for examples of the similar spawn
// functions.
#include <stdio.h>
#include <conio.h>
#include <process.h>
char *my_env[] = // Environment for exec?e
{
"THIS=environment will be",
"PASSED=to new process by",
"the EXEC=functions",
NULL
};
int main( int ac, char* av[] )
{
char *args[4];
int ch;
if( ac != 3 ){
fprintf( stderr, "Usage: %s <program> <number (1-8)>\n", av[0] );
return;
}
// Arguments for _execv?
args[0] = av[1];
args[1] = "exec??";
args[2] = "two";
args[3] = NULL;
switch( atoi( av[2] ) )
{
case 1:
_execl( av[1], av[1], "_execl", "two", NULL );
break;
case 2:
_execle( av[1], av[1], "_execle", "two", NULL, my_env );
break;
case 3:
_execlp( av[1], av[1], "_execlp", "two", NULL );
break;
case 4:
_execlpe( av[1], av[1], "_execlpe", "two", NULL, my_env );
break;
case 5:
_execv( av[1], args );
break;
case 6:
_execve( av[1], args, my_env );
break;
case 7:
_execvp( av[1], args );
break;
case 8:
_execvpe( av[1], args, my_env );
break;
default:
break;
}
// This point is reached only if exec fails.
printf( "\nProcess was not execed." );
exit( 0 );
}