本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
Office 64ビット化の壁を突破する:Win32 APIの「PtrSafe」と「LongPtr」完全実装ガイド
【背景と目的】
32bit時代のVBA資産が64bit版Officeで動作停止する問題を、PtrSafe宣言とLongPtr型の適切な定義により解決し、既存資産の継続利用と安定稼働を実現します。
【処理フロー図】
graph TD
A["VBA実行開始"] --> B{"Officeのバージョン判定"}
B -->|VBA7以上| C["PtrSafe属性を付与した宣言"]
B -->|VBA6以前| D["従来のDeclare宣言"]
C --> E{"データ型の選定"}
E -->|ポインタ/ハンドル| 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キーワードを付与
' ウィンドウハンドル(hWnd)を扱うため、戻り値はLongPtr型を使用
Declare PtrSafe Function FindWindowA Lib "user32" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As LongPtr
' 画面解像度取得など、純粋な数値(定数)を返す場合はLong型のまま
Declare PtrSafe Function GetSystemMetrics Lib "user32" ( _
ByVal nIndex As Long) As Long
#Else
' レガシー環境(32bit専用)
Declare Function FindWindowA Lib "user32" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Declare Function GetSystemMetrics Lib "user32" ( _
ByVal nIndex As Long) As Long
#End If
' 解像度取得用の定数
Const SM_CXSCREEN = 0
Const SM_CYSCREEN = 1
''' <summary>
''' 高速化処理を施しつつ、APIを利用してExcelの状態を取得するサンプル
''' </summary>
Public Sub GetExcelWindowInfo()
' 高速化設定
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
' 変数定義(ポインタ・ハンドル用にはLongPtrを使用)
#If VBA7 Then
Dim hWndExcel As LongPtr
#Else
Dim hWndExcel As Long
#End If
Dim screenWidth As Long
Dim screenHeight As Long
' 1. Win32 APIによるExcelウィンドウハンドルの取得
' クラス名 "XLMAIN" はExcel本体を指す
hWndExcel = FindWindowA("XLMAIN", Application.Caption)
' 2. 画面解像度の取得(数値データなのでLong型で受ける)
screenWidth = GetSystemMetrics(SM_CXSCREEN)
screenHeight = GetSystemMetrics(SM_CYSCREEN)
' 結果の出力
Debug.Print "--- 実行結果 ---"
Debug.Print "Window Handle: " & hWndExcel
Debug.Print "Screen Size : " & screenWidth & "x" & screenHeight
MsgBox "Excelのウィンドウハンドル: " & hWndExcel & vbCrLf & _
"現在の画面解像度: " & screenWidth & " x " & screenHeight, vbInformation
CleanUp:
' 高速化設定の解除
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
【技術解説】
#If VBA7 コンパイル条件: Office 2010で導入されたVBAバージョン7以降を判定します。これにより、古いExcel(2007以前)と最新の64bit Excelで同一のコードを共有できます。
PtrSafe属性: 64bit環境でAPIを呼び出すための「許可証」です。これがないと64bit Excelではコンパイルエラーとなります。
LongPtr型の使い分け: 最重要ポイントです。メモリのアドレス(ポインタ)やウィンドウハンドル(hWnd)は、64bit環境では64bit、32bit環境では32bitに自動調整される
LongPtrを使用します。一方、色設定やインデックス番号などの純粋な数値データは、環境を問わず32bitであるため、従来のLong型を維持します。
【注意点と運用】
安易な置換の禁止: すべての
LongをLongPtrに置換してはいけません。APIの引数仕様を確認し、それが「アドレス/ハンドル」なのか「ただの数値」なのかを見極める必要があります。構造体(Type)のパディング: APIに渡す構造体の中に
LongPtrが含まれる場合、64bit環境ではメモリ上のアライメント(配置間隔)が変わるため、データがズレてクラッシュする原因になります。複雑な構造体を扱う際は特に注意が必要です。DLL名の確認: 通常
user32やkernel32は共通ですが、外部ライブラリによっては64bit版でDLL名が異なるケースがあります。
【まとめ】
条件付きコンパイル(
VBA7)を活用し、下位互換性と最新環境への適応を両立させる。ハンドル・ポインタには
LongPtr、定数・数値データにはLongを厳密に使い分ける。API実装後は、必ず32bit/64bit両方の実機で異常終了(強制終了)がないか検証する。

