先回紹介したWaitForSingleObject関数を使ってプロセスを監視する方法で、対象をMicrosoft Excelにした場合に、困ることがあります。例えば、既にExcelが起動していた場合など、バージョンによってはプロセスが統合されてしまいWaitForSingleObject関数が正しく機能しません。
Excel 2013での仕様変更
Excelはバージョン2013からMDIからSDIへの仕様変更がされています。(Excel 2013 からのウィンドウ管理方法変更について – Japan Office Developer Support Blog)
要は、2010までのExcelは1つのアプリ画面内で複数のブック(スプレッドシート)が開いていた表示方法が、2013以降は1つのアプリ画面に1つのブックが表示されるようになりました。
これに伴い、起動した際のプロセスの取り扱いが次のようになっています。
操作 | Excel 2010 以前 | Excel 2013 以降 |
プログラムを起動 | 新規 | 既存 |
ファイルを開く | 既存 | 既存 |
オブジェクト生成(CreateObject) | 新規 | 新規 |
OLE埋め込みオブジェクト | 既存 | 既存 |
Excelを起動した場合だけ動作が変更になっています。例えば、既に別のブックが開かれている場合(Excelのプロセスが存在する場合)には、後からExcelを起動した場合でも既に存在するプロセスに統合されて起動するようになります。
WaitForSingleObject
話をプロセス監視に戻すと、WaitForSingleObject関数の場合、パラメタで受け渡されたプロセスのハンドルを使って監視するように設計されています。
例えば、Excelが起動した状態で、次のコードを走らせた場合には正しく動作がしません。
PROCESS_INFORMATION procInfo; STARTUPINFO startUpInfo; ZeroMemory(&procInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&startUpInfo, sizeof(STARTUPINFO)); startUpInfo.cb = sizeof(STARTUPINFO); CString sCommandLine = "C:\Windows\Notepad.exe"; CreateProcess( NULL, sCommandLine.GetBuffer(), 0, 0, FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, 0, 0, &startUpInfo, &procInfo); sCommandLine.ReleaseBuffer(); ::WaitForSingleObject(procInfo.hProcess, INFINITE); ::CloseHandle(procInfo.hProcess);
デバッガーを使って動作を検証すると分かりますが、CreateProcess関数で、CREATE_NEW_PROCESS_GROUP、CREATE_NEW_CONSOLEなどの引数を与えて作成したプロセスは、この時点では新しいオブジェクト(クラス)として発生しています。
その後に、Excelがインスタンス(実体化)する際に仕様に合わせて既存のプロセスに統合されています。
その後の処理でWaitForSingleObject関数で監視を行う訳ですが、オブジェクトとして発生したプロセスが既存のインスタンスに統合する際に、破棄されてしまうため、終了と見なされます。(WaitForSingleObject関数にしてみれば、統合されることなど予想していないので、当然と言えば当然の処理です)
そのため、エラーにもなりません。正常処理として関数は戻り値を返却してきます。
別インスタンスで起動するオプション
Excelには様々な起動オプションがあり、その中に別インスタンスで起動してくれるオプションが使えます。
説明 | |
/x | Excel の新しいインスタンスを(別プロセスで)起動します。
excel.exe /x “c:\My Folder\book1.xlsx” |
/e | Excel が起動画面を表示せず、新しい空のブックも開かないようにします。
excel.exe /e |
その他の起動オプションは以下を参考にしてください。
Microsoft Office 製品のコマンド ライン スイッチ
私が試した場合には、/e オプションでも別インスタンスで起動してくれましたが、解説には、/x オプションで新しいインスタンス(別プロセス)で起動と説明があるので、運用するのであれば、/x を利用するべきです。
実際に先のコードを走らせると、Excelで既に新しいブックが開いている状態でもWaitForSingleObject関数で正しく処理が停止してくれました。
また、オプションはすべてのExcelのバージョンで利用できるわけでは無いので、適用するExcelのバージョンによって使い分ける必要が出てきます。
スポンサーリンク
最後までご覧いただき、ありがとうございます。