CreateProcessWithLogonW 関数 (winbase.h)
新しいプロセスとそのプライマリ スレッドを作成します。 その後、新しいプロセスは、指定された資格情報 (ユーザー、ドメイン、パスワード) のセキュリティ コンテキストで、指定された実行可能ファイルを実行します。 必要に応じて、指定したユーザーのユーザー プロファイルを読み込むことができます。
この関数は CreateProcessAsUser 関数と CreateProcessWithTokenW 関数に似ていますが、呼び出し元が LogonUser 関数を呼び出してユーザーを認証してトークンを取得する必要がない点が除きます。
構文
BOOL CreateProcessWithLogonW(
[in] LPCWSTR lpUsername,
[in, optional] LPCWSTR lpDomain,
[in] LPCWSTR lpPassword,
[in] DWORD dwLogonFlags,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
パラメーター
[in] lpUsername
ユーザーの名前です。 これは、ログオン先のユーザー アカウントの名前です。 UPN 形式の ユーザー@DNS_domain_nameを使用する場合、 lpDomain パラメーターは NULL である必要があります。
ユーザー アカウントには、ローカル コンピューターの [ローカルログオン] アクセス許可が必要です。 このアクセス許可は、ワークステーションとサーバー上のすべてのユーザーに付与されますが、ドメイン コントローラーの管理者にのみ付与されます。
[in, optional] lpDomain
アカウント データベースに lpUsername アカウントが含まれているドメインまたはサーバーの名前。 このパラメーターが NULL の場合、ユーザー名は UPN 形式で指定する必要があります。
[in] lpPassword
lpUsername アカウントのクリア テキスト パスワード。
[in] dwLogonFlags
ログオン オプション。 このパラメーターには、0 (ゼロ) または次のいずれかの値を指定できます。
[in, optional] lpApplicationName
実行するモジュールの名前。 このモジュールは、Windows ベースのアプリケーションにすることができます。 適切なサブシステムがローカル コンピューターで使用できる場合は、他の種類のモジュール (MS-DOS や OS/2 など) を使用できます。
この文字列では、実行するモジュールの完全なパスとファイル名を指定することも、部分的な名前を指定することもできます。 部分名の場合、関数は現在のドライブと現在のディレクトリを使用して仕様を完了します。 関数は検索パスを使用しません。 このパラメーターには、ファイル名拡張子を含める必要があります。既定の拡張機能は想定されません。
lpApplicationName パラメーターは NULL にすることができ、モジュール名は lpCommandLine 文字列の最初の空白で区切られたトークンである必要があります。 スペースを含む長いファイル名を使用している場合は、引用符で囲まれた文字列を使用して、ファイル名の末尾と引数の開始位置を示します。それ以外の場合、ファイル名はあいまいです。
たとえば、次の文字列はさまざまな方法で解釈できます。
"c:\program files\sub dir\program name"
システムは、次の順序で可能性を解釈しようとします。
- c:\program.exe files\sub dir\program name
- c:\program files\sub.exe dir\program 名
- c:\program files\sub dir\program.exe 名
- c:\program files\sub dir\program name.exe
実行可能モジュールが 16 ビット アプリケーションの場合、 lpApplicationName は NULL で、 lpCommandLine が指す文字列は実行可能モジュールとその引数を指定する必要があります。
[in, out, optional] lpCommandLine
実行するコマンド ライン。 この文字列の最大長は 1024 文字です。 lpApplicationName が NULL の場合、lpCommandLine のモジュール名の部分はMAX_PATH文字に制限されます。
関数は、この文字列の内容を変更できます。 したがって、このパラメーターを読み取り専用メモリ ( const 変数やリテラル文字列など) へのポインターにすることはできません。 このパラメーターが定数文字列の場合、関数によってアクセス違反が発生する可能性があります。
lpCommandLine パラメーターは NULL にすることができ、この関数は lpApplicationName が指す文字列をコマンド ラインとして使用します。
lpApplicationName と lpCommandLine の両方が NULL 以外の場合、*lpApplicationName は実行するモジュールを指定し、*lpCommandLine はコマンド ラインを指定します。 新しいプロセスでは 、GetCommandLine を 使用してコマンド ライン全体を取得できます。 C で記述されたコンソール プロセスでは、 argc 引数と argv 引数を使用してコマンド ラインを解析できます。 argv[0] はモジュール名であるため、C プログラマは通常、モジュール名をコマンド ラインの最初のトークンとして繰り返します。
lpApplicationName が NULL の場合、コマンド ラインの最初の空白で区切られたトークンはモジュール名を指定します。 スペースを含む長いファイル名を使用している場合は、引用符で囲まれた文字列を使用して、ファイル名の末尾と引数の開始位置を示します ( lpApplicationName パラメーターの説明を参照してください)。 ファイル名に拡張子が含まれていない場合は、.exe が追加されます。 したがって、ファイル名拡張子が.com場合、このパラメーターには.com拡張子を含める必要があります。 ファイル名が拡張子のないピリオドで終わる場合、またはファイル名にパスが含まれている場合、.exe は追加されません。 ファイル名にディレクトリ パスが含まれていない場合、システムは次の順序で実行可能ファイルを検索します。
- アプリケーションの読み込み元のディレクトリ。
- 親プロセスの現在のディレクトリ。
- 32 ビット Windows システム ディレクトリ。 GetSystemDirectory 関数を使用して、このディレクトリのパスを取得します。
- 16 ビット Windows システム ディレクトリ。 このディレクトリのパスを取得する関数はありませんが、検索されます。
- Windows ディレクトリ。 GetWindowsDirectory 関数を使用して、このディレクトリのパスを取得します。
- PATH 環境変数に一覧表示されているディレクトリ。 この関数は、 アプリ パス レジストリ キーで指定されたアプリケーションごとのパスを検索しないことに注意してください。 このアプリケーションごとのパスを検索シーケンスに含めるには、 ShellExecute 関数を使用します。
[in] dwCreationFlags
プロセスの作成方法を制御するフラグ。 既定では、 CREATE_DEFAULT_ERROR_MODE、 CREATE_NEW_CONSOLE、 およびCREATE_NEW_PROCESS_GROUP フラグが有効になっています。 値の一覧については、「 プロセス作成フラグ」を参照してください。
このパラメーターは、新しいプロセスの優先度クラスも制御します。これは、プロセスのスレッドのスケジュールの優先順位を決定するために使用されます。 値の一覧については、「 GetPriorityClass」を参照してください。 優先度クラス フラグが指定されていない場合、作成プロセスの優先度クラスがIDLE_PRIORITY_CLASSまたはBELOW_NORMAL_PRIORITY_CLASSでない限り、優先度クラスの既定値は NORMAL_PRIORITY_CLASS になります。 この場合、子プロセスは呼び出し元プロセスの既定の優先度クラスを受け取ります。
dwCreationFlags パラメーターの値が 0 の場合:
- このプロセスは、既定のエラー モードを取得し、新しいコンソールを作成し、新しいプロセス グループを作成します。
- 新しいプロセスの環境ブロックには ANSI 文字が含まれていると見なされます (追加情報については 、lpEnvironment パラメーターを参照してください)。
- 16 ビット Windows ベースのアプリケーションは、共有 Virtual DOS マシン (VDM) で実行されます。
[in, optional] lpEnvironment
新しいプロセスの環境ブロックへのポインター。 このパラメーターが NULL の場合、新しいプロセスでは lpUsername で指定されたユーザーのプロファイルから作成された環境が使用されます。
環境ブロックは、null で終わる文字列の null で終わるブロックで構成されます。 各文字列は次の形式です。
名前=値
等号 (=) は区切り記号として使用されるため、環境変数の名前では使用しないでください。
環境ブロックには、Unicode または ANSI 文字を含めることができます。 lpEnvironment が指す環境ブロックに Unicode 文字が含まれている場合は、dwCreationFlags にCREATE_UNICODE_ENVIRONMENTが含まれていることを確認します。
ANSI 環境ブロックは、2 つの 0 (ゼロ) バイトで終了します。最後の文字列の場合は 1 つ、ブロックを終了する場合はもう 1 つのバイトです。 Unicode 環境ブロックは、最後の文字列の場合は 2 バイト、ブロックを終了するにはさらに 2 バイトの 4 つのゼロ バイトで終了します。
特定のユーザーの環境ブロックのコピーを取得するには、 CreateEnvironmentBlock 関数を使用します。
[in, optional] lpCurrentDirectory
プロセスの現在のディレクトリへの完全なパス。 文字列では UNC パスを指定することもできます。
このパラメーターが NULL の場合、新しいプロセスの現在のドライブとディレクトリは呼び出し元のプロセスと同じです。 この機能は、主にアプリケーションを起動し、その初期ドライブと作業ディレクトリを指定する必要があるシェル用に提供されます。
[in] lpStartupInfo
STARTUPINFO 構造体へのポインター。
アプリケーションは、指定したユーザー アカウントのアクセス許可を、WinSta0\Default の場合でも、指定されたウィンドウ ステーションとデスクトップに追加する必要があります。
lpDesktop メンバーが NULL または空の文字列の場合、新しいプロセスは親プロセスのデスクトップステーションとウィンドウステーションを継承します。 アプリケーションは、継承されたウィンドウ ステーションとデスクトップに、指定したユーザー アカウントのアクセス許可を追加する必要があります。
Windows XP: CreateProcessWithLogonW は、指定されたユーザー アカウントのアクセス許可を継承されたウィンドウ ステーションとデスクトップに追加します。
STARTUPINFO のハンドルは、必要なくなったときに CloseHandle で閉じる必要があります。
[out] lpProcessInformation
プロセスへの ハンドルなど、 新しいプロセスの識別情報を受け取るPROCESS_INFORMATION構造体へのポインター。
PROCESS_INFORMATIONのハンドルは、必要ない場合は CloseHandle 関数で閉じる必要があります。
戻り値
関数が成功すると、戻り値は 0 以外になります。
関数が失敗した場合は、0 を返します。 詳細なエラー情報を得るには、GetLastError を呼び出します。
この関数は、プロセスの初期化が完了する前に が返されることに注意してください。 必要な DLL が見つからないか、初期化に失敗した場合、プロセスは終了します。 プロセスの終了状態を取得するには、 GetExitCodeProcess を呼び出します。
注釈
既定では、 CreateProcessWithLogonW は指定したユーザー プロファイルを HKEY_USERS レジストリ キーに読み込まれません。 つまり、 HKEY_CURRENT_USER レジストリ キー内の情報にアクセスすると、通常の対話型ログオンと一致する結果が生成されないことがあります。 CreateProcessWithLogonW を呼び出す前、LOGON_WITH_PROFILEを使用するか、LoadUserProfile 関数を呼び出す前に、ユーザー レジストリ ハイブをHKEY_USERSに読み込む必要があります。
lpEnvironment パラメーターが NULL の場合、新しいプロセスでは lpUserName で指定されたユーザーのプロファイルから作成された環境ブロックが使用されます。 HOMEDRIVE 変数と HOMEPATH 変数が設定されていない場合、 CreateProcessWithLogonW は、ユーザーの作業ディレクトリのドライブとパスを使用するように環境ブロックを変更します。
新しいプロセスとスレッド ハンドルを作成すると、フル アクセス権 (PROCESS_ALL_ACCESS と THREAD_ALL_ACCESS) が受け取られます。 どちらのハンドルでも、セキュリティ記述子が指定されていない場合、そのハンドルは、その型のオブジェクト ハンドルを必要とする任意の関数で使用できます。 セキュリティ記述子を指定すると、アクセスが許可される前に、以降のすべてのハンドルの使用に対してアクセス チェックが実行されます。 アクセスが拒否された場合、要求プロセスは ハンドルを使用してプロセスまたはスレッドにアクセスできません。
セキュリティ トークンを取得するには、 PROCESS_INFORMATION 構造体のプロセス ハンドルを OpenProcessToken 関数に渡します。
プロセスにはプロセス識別子が割り当てられます。 識別子は、プロセスが終了するまで有効です。 プロセスを識別するために使用することも、 OpenProcess 関数で指定してプロセスへのハンドルを開くすることもできます。 プロセス内の初期スレッドにもスレッド識別子が割り当てられます。 OpenThread 関数で指定して、スレッドへのハンドルを開くことができます。 識別子は、スレッドが終了するまで有効であり、システム内のスレッドを一意に識別するために使用できます。 これらの識別子は 、PROCESS_INFORMATIONで返されます。
呼び出し元のスレッドは WaitForInputIdle 関数を使用して、新しいプロセスが初期化を完了し、入力が保留中でないユーザー入力を待機するまで待機できます。 これは、親プロセスと子プロセスの間の同期に役立ちます。 CreateProcessWithLogonW は、新しいプロセスが初期化を完了するのを待たずに を返します。 たとえば、作成プロセスでは、新しいプロセスに関連付けられているウィンドウを検索する前に WaitForInputIdle を使用します。
プロセスをシャットダウンする推奨される方法は 、ExitProcess 関数を使用することです。この関数は、プロセスにアタッチされているすべての DLL に終了に近づくという通知を送信するためです。 プロセスをシャットダウンするその他の方法では、アタッチされている DLL には通知されません。 スレッドが ExitProcess を呼び出すと、プロセスの他のスレッドは、追加のコード (アタッチされた DLL のスレッド終了コードを含む) を実行する機会なしに終了されることに注意してください。 詳細については、「 プロセスの終了」を参照してください。
CreateProcessWithLogonW は、ターゲット ユーザーのセキュリティ コンテキストで、指定されたディレクトリと実行可能イメージにアクセスします。 実行可能イメージがネットワーク上にあり、パスにネットワーク ドライブ文字が指定されている場合、ネットワーク ドライブ文字はログオンごとに割り当てられるため、ターゲット ユーザーはネットワーク ドライブ文字を使用できません。 ネットワーク ドライブ文字を指定すると、この関数は失敗します。 実行可能イメージがネットワーク上にある場合は、UNC パスを使用します。
この関数によって作成され、同時に実行できる子プロセスの数には制限があります。 たとえば、Windows XP では、この制限は MAXIMUM_WAIT_OBJECTS*4 です。 ただし、システム全体のクォータ制限により、この多くのプロセスを作成できない場合があります。
SP2、Windows Server 2003 以降の Windows XP: 関数は呼び出し元トークンでログオン SID を使用し、"LocalSystem" アカウントのトークンにはこの SID が含まれていないため、"LocalSystem" アカウントで実行されているプロセスから CreateProcessWithLogonW を呼び出すことはできません。 代わりに、 CreateProcessAsUser 関数と LogonUser 関数を 使用します。
この関数を使用するアプリケーションをコンパイルするには、 _WIN32_WINNTを 0x0500 以降として定義します。 詳細については、「 Windows ヘッダーの使用」を参照してください。
セキュリティに関する備考
lpApplicationName パラメーターは NULL にすることができ、実行可能ファイル名は lpCommandLine の最初の空白区切り文字列である必要があります。 実行可能ファイルまたはパス名にスペースが含まれている場合、関数がスペースを解析する方法により、別の実行可能ファイルが実行される可能性があります。 関数が "MyApp.exe" ではなく"Program.exe" を実行しようとするので、次の例は避けてください。LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)
悪意のあるユーザーが "Program.exe" というアプリケーションをシステムに作成した場合、Program Files ディレクトリを使用して CreateProcessWithLogonW を誤って呼び出すプログラムは、意図したアプリケーションではなく悪意のあるユーザー アプリケーションを実行します。
この問題を回避するには、lpApplicationName に NULL を渡さないでください。 lpApplicationName に NULL を渡す場合は、次の例に示すように、lpCommandLine の実行可能パスを引用符で囲みます。
LPTSTR szCmdline[]=_tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
CreateProcessWithLogonW(..., szCmdline, ...)
例
次の例では、この関数を呼び出す方法を示します。
#include <windows.h>
#include <stdio.h>
#include <userenv.h>
void DisplayError(LPWSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpvMessageBuffer, 0, NULL);
//
//... now display this string
//
wprintf(L"ERROR: API = %s.\n", pszAPI);
wprintf(L" error code = %d.\n", GetLastError());
wprintf(L" message = %s.\n", (LPWSTR)lpvMessageBuffer);
//
// Free the buffer allocated by the system
//
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
void wmain(int argc, WCHAR *argv[])
{
DWORD dwSize;
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
WCHAR szUserProfile[256] = L"";
si.cb = sizeof(STARTUPINFO);
if (argc != 4)
{
wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
wprintf(L"\n\n");
return;
}
//
// TO DO: change NULL to '.' to use local account database
//
if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
DisplayError(L"LogonUser");
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
DisplayError(L"CreateEnvironmentBlock");
dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
DisplayError(L"GetUserProfileDirectory");
//
// TO DO: change NULL to '.' to use local account database
//
if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
LOGON_WITH_PROFILE, NULL, argv[3],
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
&si, &pi))
DisplayError(L"CreateProcessWithLogonW");
if (!DestroyEnvironmentBlock(lpvEnv))
DisplayError(L"DestroyEnvironmentBlock");
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
要件
要件 | 値 |
---|---|
サポートされている最小のクライアント | Windows XP (デスクトップ アプリのみ) |
サポートされている最小のサーバー | Windows Server 2003 (デスクトップ アプリのみ) |
対象プラットフォーム | Windows |
ヘッダー | winbase.h (Windows.h を含む) |
Library | Advapi32.lib |
[DLL] | Advapi32.dll |