アプリケーションから他のアプリケーションを起動する場合、最低限必要な記述は以下の通り。
開発環境 | Visual Studio 2022 |
---|---|
言語 | C++ |
フレームワーク | Win32 API |
動作確認 | Windows 11 Windows 10 Windows 7 |
#include <windows.h>
// 起動したいアプリケーションのフルパス(あるいはカレントフォルダーからの相対パス)と、
// 必要に応じて引数も空白区切りにて付加する。
wchar_t commandLine[] = L"アプリケーションのパスと引数";
STARTUPINFO si{};
PROCESS_INFORMATION pi{};
si.cb = sizeof(si);
// コマンドラインの実行(成功すると0以外が戻る)
if (CreateProcess(nullptr, commandLine, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi))
{
// 起動成功
//
// アプリケーションの終了まで待つ
// (待たずに処理を先に進める場合、WaitForSingleObjectとGetExitCodeProcessは不要)
WaitForSingleObject(pi.hProcess, INFINITE);
// アプリケーションの終了コードの取得
// (終了コードを使用しない場合は不要)
unsigned long exitCode;
GetExitCodeProcess(pi.hProcess, &exitCode);
// 終了コードが負の値になる場合もあるので、signedにキャストする
long ec = static_cast<long>(exitCode);
// ハンドルを閉じる
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
// 起動失敗
//
}
CreateProcessにアプリケーション(*.exe)とその引数を設定する方法は、以下の4パターンが存在する。
1番目の引数 | 2番目の引数 | |
---|---|---|
(A) | アプリケーション | nullptr |
(B) | アプリケーション | 引数 |
(C) | nullptr | アプリケーション |
(D) | nullptr | アプリケーションと引数 |
お勧めは、アプリケーションのみなら(A)(C)どちらでもよく、引数を指定する場合は(D)パターンである。なぜなら、起動したいアプリケーションのソースがC/C++にて記述されていると仮定した場合、argc、argvの値は以下のようになるからである。
argc | argv[0] | argv[1] | argv[2] | … | |
---|---|---|---|---|---|
(A) | 1 | アプリケーション | nullptr | nullptr | … |
(B) | 引数の個数 | 1番目の引数 | 2番目の引数 | 3番目の引数 | … |
(C) | 1 | アプリケーション | nullptr | nullptr | … |
(D) | 引数の個数+1 | アプリケーション | 1番目の引数 | 2番目の引数 | … |
常識的なC/C++プログラマーなら(A)(C)(D)パターンを前提としてソースを記述しているので、(B)パターンにて呼び出すと意図した動きにならない。 さらに(B)パターンでは、argv[0]に別のアプリケーションを設定することも可能なので、(具体的な悪用方法は思いつかないが)セキュリティホールとなるかもしれない。
他のプログラミング言語については確認していないが、CreateProcessの2番目の引数がコマンドライン指定と同じと考えると、無難なのは(C)(D)パターンである。
その他の注意点は、以下の通り。
- CreateProcessの2番目の引数は、const不可
- パスに空白が含まれる場合、パスをダブルクォートで括る
- Windowsバッチファイル(*.bat)を起動したい場合、「C:\Windows\System32\cmd.exe /C バッチファイルのパス 引数」
リファレンス
CreateProcessW function
https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw