ShellExecuteでファイルやURLを開く
Windows的文件やフォルダ、ウェブページを開く操作は、シェルが管理するファイル関連付けやプロトコルハンドラーへ委譲できます。ShellExecuteは、対象と実行する操作を指定して、既定のアプリケーションを起動するAPIです。
起動するアプリケーションのパスを固定せず、拡張子やhttpスキームに応じた既定動作を利用できる点が特徴です。ただし、関連付けやユーザー設定によって起動先が変わり、起動要求の成功と対象処理の完了は区別する必要があります。
関数の役割と成功判定
戻り値の型はHINSTANCEですが、後続の処理でハンドルとして使うためのものではありません。成功値は32より大きく、失敗値は32以下です。失敗コードには、ファイルが見つからないSE_ERR_FNFや関連付けがないSE_ERR_NOASSOCなどがあります。
失敗コードだけでは原因を詳しく判別できません。また、ShellExecute失敗後にGetLastErrorを呼んでも、安定したエラー情報を得られるとは限りません。
| 観点 | ShellExecute | ShellExecuteEx |
|---|---|---|
| 呼び出し形式 | 関数の引数で指定 | SHELLEXECUTEINFO構造体で指定 |
| 成功判定 | 戻り値が32より大きい | TRUEが返る |
| 失敗時の情報 | 失敗コードの範囲は限定的 | FALSEの直後にGetLastErrorを確認できる |
| プロセス | プロセスハンドルを取得できない | SEE_MASK_NOCLOSEPROCESSで取得できる |
| エラー表示 | 標準のシェル動作に従う | SEE_MASK_FLAG_NO_UIで関数自身_customize抑制できる |
詳細な診断やプロセス管理が必要ならShellExecuteExを使います。SHELLEXECUTEINFOを初期化し、fMaskへSEE_MASK_NOCLOSEPROCESSを指定すると、起動したプロセスのハンドルを取得できます。
Unicode版を使った呼び出し
文字コードに依存しない実装にはShellExecuteWを使います。UNICODEが定義されたヘッダーでは、ShellExecuteマクロもShellExecuteWに展開されます。
#include <windows.h>
#include <shellapi.h>
#include <cstdint>
HINSTANCE result = ShellExecuteW(
nullptr, // 親ウィンドウ
L"open", // 実行する操作
L"C:\\Users\\Public\\sample.pdf", // 開く対象
nullptr, // 追加の引数
nullptr, // 作業ディレクトリ
SW_SHOWNORMAL // 表示方法
);
if (reinterpret_cast<std::intptr_t>(result) <= 32) {
// 起動失敗を処理する
}
各引数は、親ウィンドウ、実行する操作、対象、追加引数、作業ディレクトリ、表示方法を表します。lpParametersの引用符や空白は、実行側の引数解析に合わせて適切に処理します。lpDirectoryは起動プロセスの作業ディレクトリであり、呼び出し元プロセスのカレントディレクトリは変更しません。
呼び出し成功は、表示や編集が終わったことを意味しません。プロセス終了まで待つ必要がある場面では、ShellExecuteExで取得したハンドルを使い、WaitForSingleObjectで待機してからCloseHandleで解放します。
文字列とパスを安全に扱う
日本語を含むパスを扱うなら、文字列型を明示したShellExecuteWが基本です。ファイル名の文字コードと、関連付け先のアプリケーションが受け取る文字コードは別問題なので、後者まで同一と仮定しないことが重要です。
ShellExecuteAはANSIコードページを使うため、UTF-8の文字列をそのまま渡しても解釈は保証されません。- 空白を含むパスは
lpFileへそのまま渡し、引用符で囲む必要はありません。 lpParametersは単一のnull終端文字列です。複数の引数は、実行側が解析できる形へ整えます。- 相対パスは呼び出し時のカレントディレクトリに依存します。安定させるなら
GetFullPathNameWなどで絶対パス化します。 - ドライブ付きパスとUNCパスを指定できますが、存在確認とアクセス権限はWindowsに委ねられます。
httpやhttpsなどのURLは、プロトコルハンドラーへ渡されます。通常はブラウザーが開きますが、ユーザーが別の既定アプリを変更している場合があります。特定の実行ファイルへ固定依靠せず、関連付けの委譲機構を利用するのがこのAPIの役割です。
実行操作と権限の制御
lpOperationにはopenやexploreなどの実行操作を指定します。関連付け deed разрешен動詞や権限昇格動詞には、用途に応じた制限が必要です。
権限昇格を使う場面では、要求がユーザーに明示されているかを確認します。仕様に迷った際は、API仕様の参考先も利用できます。
- 動詞は
openなど許可した値だけを使い、外部入力をそのまま指定しません。 - 引用符を含む引数は解析形式に合わせて整え、入力値をそのまま連結しません。
- ダウンロードした実行ファイルは、想定した場所と署名を確認してから開きます。
SEE_MASK_FLAG_NO_UIは関数自身が出すエラー画面を抑えますが、セキュリティ確認画面は抑制しません。runasによる権限昇格では、昇格要求がキャンセルされた場合も失敗として扱います。
実務で押さえる基準
単純な既定動作の起動ならShellExecuteで十分です。失敗原因の収集やプロセス待機まで行う場合は、ShellExecuteExとSHELLEXECUTEINFOが適します。
文字列入力を扱う実装ではShellExecuteWを選び、権限昇格や入力検証を省略しないことも確認します。ShellExecuteは関連付け処理の委譲と起動要求を担うAPIです。関連付けに委譲すること、32を超えた戻り値だけを成功とすること、処理の完了は別に確認することを覚えておいてください。