32bit/64bit Office共存!Win32 APIを安全に呼び出すVBA実装ガイド

Tech

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

32bit/64bit Office共存!Win32 APIを安全に呼び出すVBA実装ガイド

【背景と目的】

32bit版から64bit版Excelへの移行時に発生するAPIコンパイルエラーを解消し、ハンドル操作や高精度計測を安全に実現する手法を解説します。

【処理フロー図】

graph TD
A["マクロ実行開始"] --> B{"VBAバージョン判定"}
B -- VBA7以降 --> C["PtrSafe属性を付与して宣言"]
B -- VBA6以前 --> D["従来のDeclare宣言を適用"]
C --> E["LongPtr型でハンドル/ポインタを処理"]
D --> E
E --> F["API関数の実行"]
F --> G["結果の戻しとメモリ解放"]
G --> H["終了"]

【実装:VBAコード】

Option Explicit

' --- Win32 API 宣言セクション ---
' VBA7(Office 2010以降)であればPtrSafeを使用
#If VBA7 Then

    ' システムの起動時間をミリ秒単位で取得(戻り値は常に32bitのLongでOK)
    Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long

    ' ウィンドウハンドルを取得(ハンドルは環境によりサイズが変わるためLongPtrを使用)
    Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
#Else

    ' 旧バージョン(32bit)用宣言
    Declare Function GetTickCount Lib "kernel32" () As Long
    Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
#End If

''' <summary>
''' APIを使用した高速計測とウィンドウハンドルの取得例
''' </summary>
Sub ExecuteApiLogic()
    Dim startTime As Long
    Dim endTime As Long
    Dim i As Long
    Dim targetHwnd As LongPtr ' 64bit環境では8バイト、32bitでは4バイトに自動調整

    ' 高速化設定
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
    End With

    On Error GoTo ErrorHandler

    ' 1. ウィンドウハンドルの取得例(自身のExcelウィンドウを探す)
    targetHwnd = FindWindow("XLMAIN", Application.Caption)
    Debug.Print "Window Handle: " & targetHwnd

    ' 2. 高精度タイマーによるループ処理の計測
    startTime = GetTickCount()

    ' ダミーの重い処理(配列処理を推奨)
    Dim dataArray(1 To 10000) As Long
    For i = 1 To 10000
        dataArray(i) = i * 2
    Next i

    endTime = GetTickCount()

    ' 終了報告
    MsgBox "処理が完了しました。" & vbCrLf & _
           "実行時間: " & (endTime - startTime) & " ms" & vbCrLf & _
           "HWND: " & targetHwnd, vbInformation

CleanUp:
    ' 設定の復元
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
    End With
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

【技術解説】

  1. VBA7とPtrSafe: Office 2010以降のVBA(VBA7)では、API宣言に PtrSafe キーワードを記述しないと64bit環境でコンパイルエラーとなります。これは「このAPI呼び出しは64bitセーフである」とプログラマが明示する仕組みです。

  2. LongPtr型の重要性: メモリアドレスやウィンドウハンドル(HWND)を格納する変数には LongPtr を使用します。これにより、32bit環境では4バイト(Long相当)、64bit環境では8バイト(LongLong相当)として動作し、メモリ溢れやクラッシュを防止します。

  3. 条件付きコンパイル: #If VBA7 Then を用いることで、古いバージョンのOffice(VBA6以前)との互換性を維持しつつ、最新環境に対応した宣言を共存させています。

【注意点と運用】

  • 戻り値の型: GetTickCount のように、戻り値がハンドルではなく「数値(ミリ秒)」である場合は、64bit環境でも Long(4バイト)のままにする必要があります。何でも LongPtr にすれば良いわけではありません。

  • エイリアスの確認: FindWindowA(ANSI版)と FindWindowW(Unicode版)の選択に注意してください。通常、VBAの内部文字列はUnicodeですが、API宣言時に String を渡すと自動でANSIに変換されるため FindWindowA が一般的に使われます。

  • 参照設定の不要: 本手法はWin32 APIを直接呼び出すため、DLLへの参照設定は不要ですが、引数の定義ミスは即座にアプリケーションの強制終了(ABEND)を招きます。

【まとめ】

  • 宣言の統一: #If VBA7 を使い、常に PtrSafeLongPtr をセットで検討する。

  • 型の使い分け: ハンドルやポインタは LongPtr、単なる数値データは Long を維持する。

  • エラー制御: API呼び出し前後での Application 設定の復元を徹底し、異常終了に備える。

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

コメント

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