Excel ワークブックをバッチ プロセス (JobScheduler の下) で実行できるようにするために、C# で Excel のラッパーを作成しました。私の問題はこれです...
コードの実行に時間がかかりすぎるか、ジョブ スケジューラを介して終了する必要がある場合、ラッパーはこの終了イベントを処理する必要があります。この目的のために、私は追加しました
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
コードに。ConsoleCtrlCheck メソッドで、共通の終了ルーチンを呼び出します (通常または終了の状況で使用されます)。このルーティングは、MS の推奨に従って次のことを行います。
ワークブックを
閉じて解放します Excel
ガベージ コレクションを閉じて解放します
その後、呼び出された Excel メソッド (エントリ ポイント) のリターン コードで終了します。これはうまくいきます。
ただし、VBA コードがまだ実行中の場合、Interop オブジェクトはワークブックを閉じたり、アプリケーションを終了したりしても応答しません。これは、すべてが遅くなったり、モーダル ダイアログが発行されたりしたことが原因である可能性があります。これに対処するために、この共通ルーチンの先頭に以下を追加しました...
- KillExcel メソッドを実行する新しいスレッドを作成する
- KillExcel メソッドは、指定された期間 (通常の終了コードが機能する可能性があるため) スリープしてから、プロセスを強制終了します。
- 通常のコードが機能する場合、スレッドで Abort を呼び出します
private static void Cleanup()
{
// Give this X seconds then terminate
mKillThread = new Thread(KillExcel);
mKillThread.IsBackground = false;
mKillThread.Start();
...
// close the workbooks and excel application
// Marshal.FinalReleaseComObject etc
GC.Collect();
GC.WaitForPendingFinalizers();
// Not sure if necessary but makes sure Process gone
try
{
Process p = Process.GetProcessById(mExcelPid);
p.WaitForExit();
}
catch(ArgumentException)
{}
mKillThread.Abort();
}
private static void KillExcel()
{
Thread.Sleep(Settings.Default.KillWaitMilliSeconds);
if (mLog.IsInfoEnabled)
mLog.Info(string.Format("Waited {0} seconds, killing Excel process [{1}]",Settings.Default.KillWaitMilliSeconds/1000, mExcelPid));
try
{
Process p = Process.GetProcessById(mExcelPid);
if (!p.HasExited)
p.Kill();
}
catch(ArgumentException)
{
}
}
私の質問は、これについてもっと良い方法がありますか、それともジョブ終了イベントでExcelプロセスが確実に削除されるようにするために必要な方法ですか?