32bit環境で動いていたDeclare文が64bit Officeに移行した途端に軒並みエラーを吐き、PtrSafeの付け忘れだと気づくまでかなり調べ回りました。Win32 APIをVBAから呼ぶ際の型合わせで詰まった点を整理しています。
Declare 構文の基本
図1: Declare構文とPtrSafeによる64bit対応
' 関数を宣言する場合
Declare [PtrSafe] Function 関数名 Lib "DLL名" [Alias "実際の関数名"] _
([引数リスト]) As 戻り値型
' Sub(戻り値なし)を宣言する場合
Declare [PtrSafe] Sub 関数名 Lib "DLL名" [Alias "実際の関数名"] _
([引数リスト])
64bit 対応:PtrSafe と LongPtr
| 項目 | 32bit VBA | 64bit VBA(Excel 2010以降) |
|---|---|---|
PtrSafe | 不要(書いても無視) | 必須(ないとコンパイルエラー) |
| ポインタ型 | Long | LongPtr(32bitでは Long, 64bitでは LongLong相当) |
| ハンドル型 | Long | LongPtr |
' #If VBA7 で 64bit VBA を判定
#If VBA7 Then
' 64bit Excel 2010 以降
Declare PtrSafe Function Sleep Lib "kernel32" (ByVal ms As Long): End Declare
#Else
' 32bit(旧環境)
Declare Function Sleep Lib "kernel32" (ByVal ms As Long): End Declare
#End If
よく使うAPI宣言集
Option Explicit
' ── スリープ(ミリ秒単位)──
#If VBA7 Then
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
' ── ファイルを関連付けアプリで開く ──
#If VBA7 Then
Public Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As LongPtr, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As LongPtr
#Else
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
' ── ウィンドウハンドル取得 ──
#If VBA7 Then
Public Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
#Else
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
#End If
使用例:スリープ・ファイルを開く
Sub ApiUsageExamples()
' 2秒待機(Waitより精度が高い)
Sleep 2000
Debug.Print "2秒後"
' PDF をデフォルトビューアで開く
ShellExecute 0, "Open", "C:\data\report.pdf", vbNullString, vbNullString, 1
End Sub
注意事項
⚠️ APIの誤使用はExcelごとクラッシュする
引数の型ミス・ポインタの渡し方を間違えると、VBAではなくExcelプロセス自体がクラッシュします。必ず公式ドキュメントで引数の型を確認し、テスト環境で十分に検証してください。
まとめ
Win32 APIを使うと VBA 標準機能の限界(精度・OS機能へのアクセス)を突破できます。64bit 対応は #If VBA7 + PtrSafe + LongPtr の3点セットが定石です。
✅ 次の章では…
PART 14 では PowerShellとの連携 を解説します。WScript.Shell でVBAからPowerShellコマンドを呼び出すパターンを紹介します。
VBA API宣言でよくある誤り
Win32 APIのDeclare宣言は64bit対応を誤るとExcelがクラッシュする危険な問題を引き起こします。代表的な誤りを整理します。
| 誤り/失敗パターン | 何が起きるか | 正しい対処/防止策 |
|---|---|---|
| 64bit ExcelでPtrSafeなしのDeclareを使う | コンパイルエラーが発生し、そのモジュールのマクロが一切実行できなくなる | Office 2010以降はDeclare PtrSafeを使い、LongPtrでポインタ型を宣言して32bit/64bitを共存させる |
| APIの戻り値エラーを確認しない | API呼び出しが失敗してもVBAは正常終了し、不正な状態のまま処理が続いてデータが壊れる | 戻り値が0またはNullの場合はエラーとして扱い、必要に応じてGetLastError APIでエラーコードを取得する |
| String型引数の文字コードを考慮せずに渡す | Unicode文字列をANSI APIに渡すと文字化けが発生し、期待した動作をしない | StrPtr/StrConvでUnicode/ANSI変換を明示するか、W系(Unicode版)のAPI関数を使用する |