いつもお世話になっております、macです。
VC++で作成した実行モジュールで、現在のプロセスをチェックして
ウィンドウは閉じているが、プロセスだけが残っているEXCELの
プロセスを強制終了するプログラムを作成しています。
以下にソースを載せます。
ここから ****
// ハンドルの取得
HANDLE hSnap;
if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) ==
INVALID_HANDLE_VALUE) {
return;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
UINT len = 0;
TCHAR buf[4048];
// 全てのプロセスをチェックする
BOOL bResult = Process32First(hSnap, &pe);
while(bResult){
// 次を取得
bResult = Process32Next(hSnap, &pe);
// EXCELの場合
if (!strcmp(pe.szExeFile, EXCEL.EXE)) {
// プロセスIDからハンドルの取得
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
pe.th32ProcessID);
// プロセスを閉じる
DWORD dwExitCode = 0;
GetExitCodeProcess(hProcess, &dwExitCode);
CloseHandle(hProcess);
}
}
CloseHandle(hSnap);
ここまで **********
ところが、ここの処理を通った後でもEXCELが終了しません。
プロセスIDからHANDLEは取得できていますが、違うHANDLEを取ってきて
しまっているのでしょうか?
過去ログを見て、「Knowledge Base JP175030」を調べてみましたが、
ちょっと違うようです。
どなたがご教授お願いします。
開発環境
WindowsXP VC++6.0 Excel 2000
Excelを終了させるという処理が入っていませんから当然です。
GetExitCodeProcessは該当プロセスの終了コードを(終了していれば)取得するAPIであっ
て,
プロセスを終了させるAPIではありません。
そして,安全にプロセスを終了させる方法は存在しません。
COMを使って終了させることができるかもしれませんが,
そもそもExcelがなぜそういう状態になったのかわからないのですから,
COMの制御を受け付けるとは限りません。
TerminateProcessを使えば,強制終了させることはできますが,
その場合,正常終了ではない以上,データの破損があるかもしれません。
YuO様、回答ありがとうございます。
TerminateProcessを追加したら、Excelのプロセスを消すことが出来ました。
なぜExcelのプロセスが残ってしまうかというと、以前このラウンジで
質問した通りです。
以下にURLを載せます。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200512/05120046.txt
ところで、上記の方法で試してみたところ、Excelのプロセスは消えましたが、
対象以外のExcelが起動している場合、そちらも消えてしまいます。
ExcelApplicationから起動したExcelのプロセスIDまたはHANDLE等、他のExcel
と区別できるような値は取得できるのでしょうか?
> ところで、上記の方法で試してみたところ、Excelのプロセスは消えましたが、
> 対象以外のExcelが起動している場合、そちらも消えてしまいます。
普通 Excel は複数のファイルを単一プロセスで開きます。
本当に複数の excel.exe が起動している状態でそうなりますか?
上記のコードだと「EXCEL.EXE」という実行ファイル名のプロセスは
片っ端から終わらせるようなコードみたいなので全部終わらせてしまいそうですね。
ただ、dairygoodsさんが指摘されている部分もあると思うので
ちゃんと確認しないと何とも言えないような気がします。
ちなみに元々のプロセスが残ってしまうと言う問題は呼び出している
プログラム側に問題が無くても起こってしまうような話なんでしょうか。
残るからには何か問題があるような気がしてならないのですけれど。
dairygoods様、PATIO様、回答ありがとうございます。
>> ところで、上記の方法で試してみたところ、Excelのプロセスは消えましたが、
>> 対象以外のExcelが起動している場合、そちらも消えてしまいます。
> 普通 Excel は複数のファイルを単一プロセスで開きます。
> 本当に複数の excel.exe が起動している状態でそうなりますか?
起動中のExcelにBookを追加するのではなく、新しくExcelを起動すると、
起動した分のプロセスが存在します。
> ちなみに元々のプロセスが残ってしまうと言う問題は呼び出している
> プログラム側に問題が無くても起こってしまうような話なんでしょうか。
> 残るからには何か問題があるような気がしてならないのですけれど。
確かにその通りです。
ですが、いろいろ試してみましたが変化はありませんでした。
そのためこのような強制終了の手段をとるようにしようと考えました。
潜在的な不具合を抱えていると言うことは無いですか?
気がついていないだけでメモリは壊しているようなパターンと言うのもありえると思うの
ですが。
正しく処理しているのにプロセスが終了しないと言う前例でもあればわかるんですが、
そうでない場合は対処療法を考えるよりも呼び出し側のプログラムをチェックしなおした方が
良いのではないかと言う気がします。
どなたか、呼び出し側に問題が無いのにEXCELのプロセスが残ると言うような例を
ご存知の方はいらっしゃいますか?
Excelのプロセスが消えない現象についてですが
私の現在の仕事でも、とあるソースコードの中でそんな事を訴えながら
1. 処理開始前のプロセスを列挙する。
2. 処理。 (この中でExcelを起動したりする)
3. 終了処理。処理開始前に列挙したプロセスと現在のプロセスを比較し
増えちゃってるExcelプロセスをkillする。
という、なんだかなぁな処理を行っています。
殆どの原因はオブジェクトの解放がうまく行えていないからで、
たとえば下記ページ(「Visual Basic 中学校」さん)などが参考になります。
http://homepage1.nifty.com/rucio/main/technique/teq_15.htm
Excelは多少クセが強いのか?意外な操作で意外なオブジェクトを生成してしまい
それを解放しそこなう、といったパターンについて警告されています。
「呼び出し側に問題は無い」というよりは
「呼び出し側の問題に、なかなか気付きにくい」という感じでしょうか。
# おふとぴ:
# ご多分にもれず、私の仕事の件でもやはりオブジェクトの解放が
# うまく行えていなかったのですが、それを上司に報告すると
# 「……見なかった事にしてくれ」と。
# 実際に業務で使用されるコードでは無いし
# 上位の上位くらいに居る大会社様から下賜されたコードなので
# 立場的に ダメ出し できないようで。。。うちの会社、弱ぇ。。。
PATIO様、pseudo様回答ありがとうございます。
とりあえず、今のところはExcelの保存後プロセスが残っているようなら
強制終了するようにしました。
以下にソースを記述します。
// Excelを判別するCaptionをセット
m_excel.SetCaption(SetCaptionSample);
// BOOK・BOOKS・アプリケーションを閉じる
:
:
// Excelのハンドルを取得
// シートオープン時にFindWindowを使用すると、キャプションにシート名が
// 入ってしまい、不安定になるので、シートを閉じた後で行う
HWND hWnd = ::FindWindow(XLMAIN, SetCaptionSample);
if (hWnd == NULL) {
return;
}
// プロセスIDを取得
DWORD dwProcessId;
GetWindowThreadProcessId(hWnd , &dwProcessId);
// ハンドルの取得
HANDLE hSnap;
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
// ハンドルがエラー値の場合
if (hSnap == INVALID_HANDLE_VALUE) {
return;
}
// 全てのプロセスをチェックする
BOOL bResult = Process32First(hSnap, &pe);
while(bResult){
// 次を取得
bResult = Process32Next(hSnap, &pe);
// EXCELでプロセスIDが同じ場合
if (!strcmp(pe.szExeFile, EXCEL.EXE)
&& dwProcessId ==pe.th32ProcessID) {
// プロセスIDからハンドルの取得
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
pe.th32ProcessID);
// EXCELを破棄
TerminateProcess(hProcess, 0);
// プロセスを閉じる
DWORD dwExitCode = 0;
GetExitCodeProcess(hProcess, &dwExitCode);
CloseHandle(hProcess);
}
}
CloseHandle(hSnap);