Win32 API「GetTickCount」によるVBA処理時間の高精度計測と高速化実装

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

Win32 API「GetTickCount」によるVBA処理時間の高精度計測と高速化実装

【背景と目的】

VBA標準のTimer関数は精度が約15ミリ秒と荒く、高速なループ処理のボトルネック特定には不向きです。本稿ではWin32 APIを利用し、1ミリ秒単位の計測を実現します。

【処理フロー図】

graph TD
A["開始"] --> B["Win32 API 宣言"]
B --> C["計測開始時のTick取得"]
C --> D["高速化設定の適用"]
D --> E["メイン処理実行"]
E --> F["高速化設定の解除"]
F --> G["計測終了時のTick取得"]
G --> H["差分計算・結果表示"]
H --> I["終了"]

【実装:VBAコード】

Option Explicit

' --- Win32 API 宣言 (64bit/32bit両対応) ---
' GetTickCount: Windows起動後の経過時間をミリ秒単位で取得
#If VBA7 Then

    Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else

    Private Declare Function GetTickCount Lib "kernel32" () As Long
#End If

''' <summary>
''' 高精度計測を伴うデータ処理のサンプル
''' </summary>
Public Sub ExecuteHighPrecisionTask()
    Dim startTime As Long
    Dim endTime As Long
    Dim executionTime As Double

    ' 1. 計測開始
    startTime = GetTickCount()

    ' 2. 高速化設定(画面更新停止・自動計算停止)
    Call OptimizeExcel(True)

    On Error GoTo ErrorHandler

    ' 3. メイン処理(例:大量の配列処理)
    Dim i As Long
    Dim tempArray(1 To 1000000) As Long
    For i = 1 To 1000000
        tempArray(i) = i * 2 ' ダミー処理
    Next i

    ' 4. 高速化設定の解除
    Call OptimizeExcel(False)

    ' 5. 計測終了と結果算出
    endTime = GetTickCount()
    executionTime = (endTime - startTime) / 1000 ' 秒単位に変換

    MsgBox "処理が完了しました。" & vbCrLf & _
           "実行時間: " & Format(executionTime, "0.000") & " 秒", vbInformation

    Exit Sub

ErrorHandler:
    Call OptimizeExcel(False)
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub

''' <summary>
''' Excelの動作設定を切り替えて処理を高速化する
''' </summary>
Private Sub OptimizeExcel(ByVal enable As Boolean)
    With Application
        If enable Then
            .ScreenUpdating = False     ' 画面更新停止
            .Calculation = xlCalculationManual ' 自動計算停止
            .EnableEvents = False       ' イベント停止
        Else
            .ScreenUpdating = True
            .Calculation = xlCalculationAutomatic
            .EnableEvents = True
        End If
    End With
End Sub

【技術解説】

  1. Win32 APIの採用理由: VBA標準のTimer関数はシステム時刻に基づきますが、GetTickCountはシステムの稼働時間を参照するため、より高精度(1ms単位)な計測が可能です。

  2. PtrSafe 宣言: VBA7(Excel 2010以降)および64bit環境で動作させるため、条件付きコンパイルとPtrSafeキーワードが必須となります。

  3. 最適化関数の分離: ScreenUpdating等の設定変更を独立したサブプロシージャ(OptimizeExcel)にすることで、再利用性を高め、エラー発生時の復旧漏れを防ぎます。

【注意点と運用】

  • 49.7日の壁: GetTickCountの戻り値は32bit符号付き整数の範囲を超えるため、Windowsを連続稼働させて約49.7日経過すると数値がループ(オーバーフローのようにリセット)されます。サーバーOS等で長時間稼働させる場合は注意が必要です。

  • エラーハンドリング: 高速化設定(ScreenUpdating = False)中にマクロが中断すると、Excelの操作ができなくなる(画面が固まる)ため、必ずOn Error句で設定を元に戻す処理を入れてください。

  • さらなる精度: さらにマイクロ秒単位の精度が必要な場合は、QueryPerformanceCounter APIの検討が必要ですが、通常の実務改善であればGetTickCountで十分です。

【まとめ】

  1. ボトルネックの可視化: 1ms単位で計測することで、どの処理が遅いのかを正確に特定する。

  2. 一括設定の定石化: 画面更新停止等の「高速化セット」をテンプレート化して適用する。

  3. 環境互換性の確保: PtrSafeを用いた宣言により、組織内の多様なExcelバージョンに対応させる。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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