Microsoft Access を終了してもバックグラウンドプロセスが残ってしまうことがかなりの頻度で発生するようになった。
中途半端な終わり方をしているので、laccdbファイルが残ってしまい、使用中なので削除できないという。
開きなおそうとしても、今度は開けない。
やむなくタスクマネージャーからプロセスを終了するのだが、これでいいのか?
そもそも、たとえユーザーのプログラミングに不備があっても終了くらいはきちんとできるようにするべきだと思う。
アクセスを終了するdocmd.quitの代わりに、vbaでプロセスを終了させるという荒業もやってみたが、バックグラウンドで何かの後始末をしているのにそれを強制的に終了させるのは、痛い。
そこで、Windows10には標準で入っていて、特別な設定をしなくても使える、バッチ処理にやってもらうことにした。
ネットで調べながら、コマンドプロンプトで試し、メモ帳に列挙して、batファイルを作った。
batファイルを作るときの文法とコマンドプロンプトの文法が微妙に違うので試行錯誤。
ネットでは、FOR /L に続くのは%%[アルファベット一文字]となっているのだが、コマンドプロンプトではエラーになる。
コマンドプロンプトで動作してもバッチファイルにするとエラーになる。%なのか%%なのか。
変数も文字列と数が明確に分けられていないので、IFの条件式が、equ でも == でも成立しない。原因がわかるまで悩んだ。
これをACCESSのテーブルに読み込んで、ACCESSの終了時にテキスト出力をして.batファイルを作成し、docmd.quitの直前にShellで実行させる。ACCESS自体は、本来の終了方法なのでデータが壊れる心配はまずない。
ACCESSが最適化などの終了作業をしている間はCPU使用率がゼロにはならないので、作業中に突然終了にはならない。はず。
タスクマネージャーを見ながら、手作業でやればできないこともないけれども、美しくない。
プロセスが終了すれば、laccdbファイルもバッチ処理から簡単に削除できる。ACCESSファイルとパスをバッチファイルに書き込みたかったので、終了の都度、新しいバッチファイルを書き出すことにした。
@echo off
rem MSACCESS.EXEがプロセスとして存在しているかを確認
tasklist | find "MSACCESS.EXE" > NUL
if %ERRORLEVEL% == 0 (
rem 存在している場合は強制終了へ
goto FORCED
) else (
goto END
)
rem
rem 強制終了処理
:FORCED
rem 一応10秒ほど待つ
timeout /t 10 /nobreak >nul
rem 前回作成した一時ファイルを削除
del %TEMP%\wmic.out
rem 実行されているプロセスからMSACCESSでCPU使用率が0のPID、Name、CPU使用率(ゼロに決まっているのだが)を一時ファイルwmic.outに出力する
WMIC PATH Win32_PerfFormattedData_PerfProc_Process WHERE "Name = 'MSACCESS' and PercentUserTime = 0" GET Name,IDProcess,PercentUserTime /FORMAT:CSV | more > %TEMP%\wmic.out
setlocal enabledelayedexpansion
rem 一時ファイルからCPU使用率を読み出す。
FOR /l %%r IN (0,1,20) DO (
FOR /F "delims=, tokens=2,3,4" %%i IN (%TEMP%\wmic.out) DO (SET PID=%%i&SET Name=%%j&SET CPUPer=%%k)
rem 1をかけると明らかに数字になる(表示すると0だが見えない文字が含まれているようだ)
set /a CPUPer = !CPUPer! * 1
if !CPUPer! equ 0 (
rem ゼロの場合は、プロセスは存在しているが作業は終わっていると判断して、強制終了
TASKKILL /F /IM MSACCESS.EXE /T
echo 不要なアクセスプロセスを停止しました
pause
goto END
)
)
:END
endlocal