【VBA】64bit/32bit両対応!Win32 APIを安全に呼び出す実務的実装ガイド

Tech

[Meta: VBA_WIN32API_MIGRATION]

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

【VBA】64bit/32bit両対応!Win32 APIを安全に呼び出す実務的実装ガイド

【背景と目的】

Officeの64bit化に伴い、従来のAPI宣言では「コンパイルエラー」が発生します。互換性を維持しつつ、APIによる高速処理を安全に実装する手法を解説します。

【処理フロー図】

graph TD
A["VBA実行開始"] --> B{"VBAのバージョン判定"}
B -- VBA7以降 --> C["PtrSafe属性を付与して宣言"]
B -- それ以前 --> D["従来のDeclareで宣言"]
C --> E{"OSビット数の判定"}
E -- 64bit型 --> F["LongPtrを使用"]
E -- 32bit型 --> G["Longを使用"]
F --> H["API関数の実行"]
G --> H
H --> I["終了"]

【実装:VBAコード】

Option Explicit

' --- Win32 API 宣言セクション ---
' VBA7 (Office 2010以降) かどうかで宣言を分岐
#If VBA7 Then

    ' 64bit/32bit共通のPtrSafe宣言
    ' Sleep: 指定ミリ秒待機するAPI
    Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

    ' GetTickCount: OS起動後の経過時間をミリ秒で取得(高速計測用)
    Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else

    ' 旧バージョン用宣言
    Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    Declare Function GetTickCount Lib "kernel32" () As Long
#End If

''' <summary>
''' 大容量データを配列で高速処理し、APIで処理時間を計測するサンプル
''' </summary>
Sub HighSpeedProcessExample()
    Dim startTime As Long
    Dim endTime As Long
    Dim i As Long
    Dim dataArray As Variant
    Dim maxRows As Long: maxRows = 100000

    ' 画面更新と計算を停止して高速化
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
    End With

    ' APIで開始時間を取得
    startTime = GetTickCount()

    ' 1. 配列への取り込み(セルへの直接アクセスを避ける)
    ReDim dataArray(1 To maxRows, 1 To 1)

    ' 2. メモリ上でのループ処理
    For i = 1 To maxRows
        dataArray(i, 1) = "Data_" & i

        ' 負荷シミュレーション(特定の条件でわずかに待機)
        If i = 50000 Then
            ' Win32 APIによる待機(DoEventsより低負荷)
            Sleep 500 
        End If
    Next i

    ' 3. シートへの一括書き出し
    Range("A1").Resize(maxRows, 1).Value = dataArray

    ' APIで終了時間を取得
    endTime = GetTickCount()

    ' 設定の復元
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
    End With

    MsgBox "処理が完了しました。" & vbCrLf & _
           "実行時間: " & (endTime - startTime) & " ミリ秒", vbInformation
End Sub

【技術解説】

  1. VBA7 構文(条件付きコンパイル): Office 2010以降のVBA環境かどうかを判定します。PtrSafeキーワードはVBA7以降で必須であり、これがないと64bit環境では構文エラーとなります。

  2. LongPtr 型の使い分け: 今回のSleepの引数やGetTickCountの戻り値は「時間(数値)」であるため、64bit環境でもLong(32bit整数)のままです。一方、ウィンドウハンドル(HWND)やポインタ(AddressOf等)を扱う場合は、環境に合わせてサイズが変わるLongPtrを使用する必要があります。

  3. 高速化の理論: APIのSleepは、VBAのWaitメソッドと異なり、Excelのプロセスを完全に一時停止させるため、CPUリソースの消費を抑えた待機が可能です。また、配列処理とScreenUpdating = Falseを併用することで、描画負荷を最小化しています。

【注意点と運用】

  • データ型の不一致: 64bit環境でポインタにLong(32bit)を使用すると、メモリ番地が切り捨てられ、最悪の場合Excelが強制終了(クラッシュ)します。ハンドルを扱う際は必ずLongPtrを適用してください。

  • API名の誤字: Lib "kernel32" などのライブラリ名や関数名は、大文字小文字を区別しませんが、スペルミスがあると「ファイルが見つかりません」という実行時エラーになります。

  • 検証環境の確保: 開発機が32bitでも、配布先が64bitであることは多々あります。APIを使用する場合は必ず両方の環境でのテストを推奨します。

【まとめ】

  1. 宣言の共通化: #If VBA7 を使い、PtrSafe を付与して32/64bit両環境でのコンパイルを通す。

  2. 型選択の規約: ハンドル・ポインタには LongPtr、サイズ・カウントには Long を適用する。

  3. パフォーマンス: 描画停止(ScreenUpdating)とWin32 APIを組み合わせ、実務に耐えうる高速ロジックを構築する。

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

コメント

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