Excel VBAで32ビットと64ビットで変更する方法をお探しですね。
広告
Excel VBAが「PtrSafe属性が必要です」エラーで動かないときの対処法【32bit/64bit問題を解決】
Excel VBAのマクロを別のパソコンで実行したとき、「Declareステートメントを更新してください」「PtrSafe属性が必要です」「型が一致しません」といったエラーが出て止まってしまうことがあります。
特に、以前から使っていたマクロを新しいPCや64bit版Excelに移したときに起こりやすい現象です。
原因はExcelの32bit版・64bit版の違い、そしてWindows APIを呼び出すVBAコードの互換性にあることがほとんどです。
この記事では、VBAが動かないときに確認すべき32bit版と64bit版Excelの違い、PtrSafe・LongPtr・LongLongの考え方、実際の修正方法までをわかりやすく解説します。
1. VBAが動かない原因は「Excelのbit数」の違いかも
VBAが急に動かなくなったとき、多くの人はExcelのバージョンやWindowsの更新、参照設定の不足などを疑います。
もちろんそれらが原因のこともありますが、**Windows APIを使っているマクロでは、Excelが32bit版か64bit版かの違いが大きく影響**します。
ここで重要なのは、**Windowsが64bitかどうかではなく、実際に動いているExcelが32bit版か64bit版か**という点です。
64bit版Windows上でも32bit版Excelは普通に動くので、「PCが64bitだからExcelも64bit」とは限りません。
32bit版と64bit版の何が違うの?
32bit版Excelと64bit版Excelの大きな違いは、**扱えるメモリアドレスの大きさ**です。
普通のセル操作やワークシート関数、基本的なVBA処理だけなら、bit数の違いを意識する場面はそれほど多くありません。
でも、**Windows APIのようにWindows内部の機能を直接呼び出す処理**では、ウィンドウハンドル、ポインタ、メモリアドレスなどを扱うことがあります。
これらは32bit環境と64bit環境で必要なサイズが変わるため、古い32bit向けのDeclare宣言のままでは64bit版Excelでエラーが出てしまうんです。
自分のExcelが32bitか64bitか確認する方法
Excelの「ファイル」→「アカウント」(または「Officeアカウント」)→「Excelのバージョン情報」を開くと、上部に「32ビット」または「64ビット」と書かれています。
業務でマクロを配布する場合は、自分の環境だけでなく、**利用者側のExcelのbit数も確認しておく**ことが大切です。
同じxlsmファイルでも、自分のPCでは正常に動くのに同僚のPCではエラーになる、というケースはこの違いで説明できることが多いです。
2. Windows APIとDeclareステートメントでエラーが出る理由
Windows APIって何?
Windows APIとは、Windowsが提供している機能をアプリケーションから利用するための仕組みです。
VBAでは、標準機能だけでは難しい操作を行うためにWindows APIを呼び出すことがあります。
たとえば:
– ウィンドウを最前面に表示する
– ファイルをダウンロードする
– スリープ処理を行う
– 現在のウィンドウハンドルを取得する
こういった処理をVBAから使う場合、モジュールの宣言部に**Declareステートメント**を書いて、どのDLLのどの関数を呼び出すのか、引数や戻り値の型は何かをVBAに伝えます。
古い32bit向けのコードだとエラーになる
古い32bit版Excel向けのコードでは、次のような宣言がよく使われていました。
“`vb
Declare Function SetForegroundWindow Lib “user32” _
(ByVal hWnd As Long) As Long
“`
この宣言は32bit版Excelでは問題なく動いていても、64bit版Excelでは**「DeclareステートメントにはPtrSafe属性を指定する必要があります」**といったコンパイルエラーになることがあります。
64bit版VBAでは、外部DLLを呼び出すDeclare文に対して「この宣言は64bit環境でも安全に確認済みです」という意味を持つ**PtrSafe**の記述が求められるためです。
つまりPtrSafeは単なるおまじないではなく、**64bit環境でAPI宣言を見直したことをコンパイラへ示すための印**なんです。
PtrSafeを付けるだけでは完全に解決しない
ただし、Declareの後ろにPtrSafeを付けるだけで完全に解決するとは限りません。
PtrSafeは「64bit対応の確認をした」という宣言に近いもので、**実際の引数や戻り値の型が正しいかまでは保証してくれない**からです。
32bit時代にはLong型で足りていたウィンドウハンドルやポインタが、64bit環境ではLong型に収まらない場合があります。
そのため、PtrSafeを付けたあとに「型が一致しません」という別のエラーが出たり、最悪の場合はExcelが強制終了したりすることも。
**64bit対応では、PtrSafeの追加と同時に、型の見直しまで行う必要があります。
**
3. PtrSafe対応の基本は「LongPtr」を正しく使うこと
LongPtrって何?
64bit版Excelに対応するうえで中心になるのが**LongPtr**です。
LongPtrは:
– **32bit版VBAではLongとして扱われる**
– **64bit版VBAではLongLong相当として扱われる**
という特別なデータ型です。
名前に「Ptr」とあるとおり、主に**ポインタやハンドルなど、環境によってサイズが変わる値を扱うため**に使います。
これにより、Office 2010以降のVBA7環境では、32bit版Excelと64bit版Excelの両方で動くDeclare宣言を書きやすくなっています。
実際の修正例
たとえば、ウィンドウハンドルを受け取るAPIであれば、次のように修正します。
“`vb
Declare PtrSafe Function SetForegroundWindow Lib “user32” _
(ByVal hWnd As LongPtr) As Long
“`
この例では:
1. Declareの後ろに**PtrSafe**を追加
2. hWndを**LongからLongPtr**に変更
一方で、**戻り値のAs Longはそのまま**です。
SetForegroundWindowの戻り値は成功・失敗を示すBOOL型であり、ポインタやハンドルではないため、LongPtrにする必要はありません。
全部のLongをLongPtrに変えるのは危険!
ここが非常に重要です。
**64bit対応だからといって、コード中のLongをすべてLongPtrに置き換えるのは危険**です。
APIの仕様上、32bit整数を受け取る引数までLongPtrに変えてしまうと、構造体のサイズがずれたり、意図しないメモリアクセスにつながったりする可能性があります。
LongLongとの違いは?
**LongLong**は64bitの整数を扱うデータ型で、64bit版VBAで利用できます。
しかし、**32bit版VBAでは使えない**ため、32bit版Excelと64bit版Excelの両方で同じコードを動かしたい場合には不向きです。
Windows APIのポインタやハンドルに関する引数・戻り値には、基本的に**LongLongではなくLongPtrを使う**ほうが安全で実用的です。
ただし、APIの仕様によっては純粋な64bit整数を扱うケースもあるため、最終的にはMicrosoftのドキュメントや信頼できるAPI宣言例を確認する姿勢が欠かせません。
4. 32bit版・64bit版Excelの両方で動かすための実践ポイント
Office 2010以降だけを対象にする場合
Office 2010以降のVBA7だけを対象にするなら、多くのWindows API宣言は**PtrSafeとLongPtrを使うこと**で32bit版・64bit版の両方に対応できます。
**修正の基本ルール:**
– ハンドルやポインタに該当する引数→**LongPtr**
– 座標、サイズ、フラグ、戻り値のBOOLなど→仕様に応じて**Longのまま**
迷ったときは、関数名だけで判断せず、**Windows APIの引数がHWND、HANDLE、LPARAM、WPARAM、ポインタ型などかどうか**を確認します。
これらはLongPtr候補になりやすい一方、単なる数値やフラグはLongのままでよいことが多いです。
Office 2007以前も対象に含める場合
古いOffice 2007以前も対象に含める場合は、PtrSafeやLongPtrを認識できないため、**条件付きコンパイル**を使って宣言を分ける必要があります。
条件付きコンパイルとは、実行前のコンパイル段階で環境を判定し、有効にするコードを切り替える仕組みです。
代表的な定数には:
– **VBA7**: Office 2010以降かどうか
– **Win64**: 64bit版Officeかどうか
“`vb
#If VBA7 Then
Public Declare PtrSafe Function SetForegroundWindow Lib “user32” _
(ByVal hWnd As LongPtr) As Long
#Else
Public Declare Function SetForegroundWindow Lib “user32” _
(ByVal hWnd As Long) As Long
#End If
“`
Office 2007以前を切り捨てられるなら記述はかなり簡潔になりますが、社内に古い環境が残っている場合は無視できません。
実務で安全に修正する手順
1. **エラーが出ているDeclare文を検索**し、API宣言を1つずつ確認
2. **Declare文だけでなく、そのAPIへ渡している変数や、APIの戻り値を受け取っている変数の型も見直す**
3. 宣言側をLongPtrにしても、呼び出し側の変数がLongのままだと「型が一致しません」が発生することがあるので注意
4. VarPtr、StrPtr、ObjPtrのような**アドレスを扱う関数を使っている場合は、より慎重に確認**
これらはコンパイル時には通っても、実行時にExcelが落ちる原因になることがあります。
一括置換は危険!段階的に進めよう
VBAが動かない原因を切り分けるときは、**いきなり全体を置換するのではなく、影響範囲を把握しながら進める**ことが大切です。
特に「DeclareをDeclare PtrSafeにする」「LongをLongPtrにする」という対応は方向性として正しいものの、機械的な一括置換では不具合を作り込む可能性があります。
**おすすめの進め方:**
– Microsoftが提供している64bit対応のAPI宣言例を参照
– 信頼できる技術情報を確認
– 可能であれば**32bit版Excelと64bit版Excelの両方でテスト**
自分だけが使うマクロなら一時的な修正でも済むかもしれませんが、他人に配布する業務用マクロでは、bit数の違いを前提にした設計が安定運用につながります。
まとめ:VBAの32bit・64bit問題は整理すれば怖くない
VBAの32bit・64bit問題は、最初は難しく見えますが、**考え方は整理できます**。
**押さえておくべきポイント:**
– 通常のVBA処理ではbit数の影響は小さい
– 問題になりやすいのは**Windows APIなど外部機能を呼び出す部分**
– 64bit版ExcelでDeclareエラーが出たら、**PtrSafeを追加するだけで終わらせず、ハンドルやポインタに関係するLongをLongPtrへ見直す**
– さらに、呼び出し側の変数、戻り値、条件付きコンパイルまで確認できれば、32bit版と64bit版の両方で動く堅牢なマクロに近づける
この記事の内容を参考に、一つずつ確認しながら修正を進めてみてください。
焦らず丁寧に対応すれば、必ず動くようになります!
広告
