【テクニカル・上級編】フォームの「TimerInterval」と「OnTimer」で実現する自動ログアウト機能 – Access VBA解析バイブル

スポンサーリンク

荒野のAccess開発者へ:Timerイベントで実装する「無慈悲な自動ログアウト」の極意

Accessを基幹システムとして運用する現場において、「席を外した隙にデータを覗かれる」というリスクは、管理者にとって悪夢そのものだ。クライアントサイドで動くAccessにとって、自動ログアウトの実装は「避けては通れない防壁」である。

だが、安易に`TimerInterval`を設定して終わるレベルでは、プロのエンジニアとは呼べない。今回は、システムリソースを食いつぶさず、かつ確実にセッションを終了させるための「極限の設計思想」を伝授する。

1. タイマーの設計哲学:なぜ「フォーム」なのか

Accessで時間監視を行う際、多くは「非表示のメインフォーム」に`TimerInterval`を仕込む。ここで重要なのは、「タイマーの刻み(Tick)がシステムに与える負荷」をいかに最小化するかだ。

`TimerInterval`を1000ms(1秒)に設定すれば、CPUは1秒ごとに割り込みを要求される。これを全クライアントで実行すれば、サーバーへのトラフィックやローカルのオーバーヘッドは無視できないレベルになる。

極意: 監視の精度は「1分単位」で十分だ。1秒単位の厳密さは不要である。60,000ms(1分)のインターバルを設定し、その中でWindows APIを用いて「最後にキー入力やマウス操作が行われてからの時間」を計測する。これがリソースを浪費しないエンジニアの選択だ。

2. Windows APIで「真のアイドル時間」を掴む

VBAの`Timer`関数は、その日の深夜0時からの秒数を返すだけのものであり、ユーザーが操作しているかどうかを判定できない。必要なのは、`GetLastInputInfo`というAPIだ。

以下のコードは、システムのアイドル時間をミリ秒単位で取得するモジュールである。

Option Compare Database
Option Explicit

‘ 最後の入力時間を取得するための構造体
Private Type LASTINPUTINFO
cbSize As Long
dwTime As Long
End Type

‘ User32.dllを叩く(これが最も軽量で正確な手法だ)
Private Declare PtrSafe Function GetLastInputInfo Lib “user32” (plii As LASTINPUTINFO) As Long
Private Declare PtrSafe Function GetTickCount Lib “kernel32” () As Long

‘ アイドル秒数を返す関数
Public Function GetIdleSeconds() As Long
Dim lii As LASTINPUTINFO
lii.cbSize = Len(lii)

If GetLastInputInfo(lii) Then
‘ 現在の稼働時間 – 最後の入力時間 = アイドル時間
GetIdleSeconds = (GetTickCount – lii.dwTime) / 1000
End If
End Function

3. オブジェクトのライフサイクルを意識した実装

メインフォーム(`frmSystemMonitor`)の`OnTimer`イベントに、以下のロジックを実装する。ここで重要なのは、オブジェクトの解放とアプリケーションの終了処理の分離だ。

Private Sub Form_Timer()
‘ タイムアウト値(例: 30分 = 1800秒)
Const TIMEOUT_LIMIT As Long = 1800

‘ アイドル時間を取得
If GetIdleSeconds() >= TIMEOUT_LIMIT Then
‘ 警告なしで無慈悲に終了する(必要に応じて警告ダイアログを挟む)
Call ShutdownApplication
End If
End Sub

Private Sub ShutdownApplication()
‘ フォームの終了ではなく、Applicationそのものを閉じる
‘ ダーティな状態(編集中)があれば破棄する設計が前提
On Error Resume Next

‘ すべてのフォームを閉じる
DoCmd.Close acForm, , acSaveNo

‘ 必要に応じてログを記録する処理(テーブルへの書き込み等)
‘ Debug.Print “Auto Logout: ” & Now

‘ アプリケーション終了
Application.Quit acQuitSaveNone
End Sub

4. 現場で生き残るための「保守の知見」

この仕組みを導入する際、以下の3点に注意せよ。これが「動くシステム」と「壊れないシステム」の境界線だ。

  • 排他制御の罠: `Application.Quit`を強制すると、レコードがロックされたままになる可能性がある。終了前には、フォームの`Dirty`プロパティをチェックし、`Me.Undo`を確実に実行してトランザクションをクリーンにしろ。
  • 例外処理の透明化: 開発環境でこのロジックが働くと、デバッグ作業が中断されて非常に不便だ。`If CurrentProject.Properties(“StartupForm”) = “DEBUG_MODE” Then Exit Sub` のようなフラグを持たせ、開発時には無効化できるようにしておくのが鉄則である。
  • イベントの競合: `OnTimer`で重い処理(外部APIの呼び出しなど)を併用してはならない。タイマーが処理を食うと、AccessのUIスレッドがフリーズし、ユーザーは「Accessが固まった」と勘違いしてタスクマネージャーから強制終了させる。これはDB破損の最大の原因となる。

最後に

「自動ログアウト」は単なる機能ではない。それは、システムがその境界線(境界セキュリティ)を自ら守るための、静かなる番人である。

このコードを実装する君たちのAccessは、もはや単なる事務ツールではない。運用という戦場において、君たちの代わりにシステムを守り続ける「熟練の守護者」となるはずだ。

技術を愛し、アーキテクチャに敬意を払え。それこそが、レガシーを伝説に変える唯一の道だ。

タイトルとURLをコピーしました