Claude Media
Claude CodeでVBAを64bit対応にする — Declare文のPtrSafeを直す手順

Claude CodeでVBAを64bit対応にする — Declare文のPtrSafeを直す手順

32bit前提のVBAを64bit版Officeで動かすには、Declare文のPtrSafeとLongPtrの置換が要ります。.basに書き出して洗い出し、Claude Codeに直させ、検証するまでの手順です。

Office 2010より前に書かれたVBAをMicrosoft 365の64bit版で開くと、Declare文のところで止まります。直す箇所は多くの場合 Declare の宣言に集中しているので、モジュールをテキストに書き出し、Claude Codeに洗い出しと置換を任せやすい作業です。ただし「PtrSafeを足せば終わり」ではありません。足しただけではコンパイルが通るのに、実行時に壊れる状態が残ります。この記事では、書き出し、洗い出し、置換、検証の順に、依頼文と検査用のコマンドまで示します。VBAをClaude Codeに書かせる基本はClaude CodeでExcel VBAマクロを書く手順にまとめています。

64bit版Officeで何が壊れるのか

VBAのバージョン6以前は32bit環境を前提にしています。ポインタやハンドルを表す専用の型がなく、Windows APIを呼ぶDeclare文では Long(4バイト)で受けていました。64bit環境でこれを使うと、64bitの値が32bitの型に詰め込まれて切り捨てられます。メモリの破壊、思わぬ結果、アプリケーションの異常終了につながり得ると、Microsoftのドキュメントは説明しています。

対策としてVBA7に加わった言語機能のうち、この作業で触るのは3つです。

要素種類役割
PtrSafe種類キーワード役割Declare文が64bitを対象にしていると宣言する。64bit版では必須
LongPtr種類型の別名役割32bit版ではLong、64bit版ではLongLongに解決される
LongLong種類データ型役割8バイトの整数。64bit版でのみ宣言できる

Office 2010、2013、2016は既定で32bit版がインストールされ、64bit版は導入時に選ぶ必要がありました。Office 2019とMicrosoft 365からは64bit版が既定です。Microsoftは、修正が必要なのは64bit版Officeで動かすコードだけだとも書いています。32bit版でしか使わないブックなら、急ぐ必要はありません。

直す対象はDeclare文だけではない

作業の範囲を決める根拠は、ドキュメントの要約にあります。64bit対応には次の4点が要ります。

  • すべてのDeclare文にPtrSafeを付ける
  • Declare文の中で、ポインタやハンドルを受ける引数と戻り値をLongPtrにする
  • 64bitの整数を入れる型はLongLongにする
  • ポインタやハンドル、64bit整数を含むユーザー定義型(UDT)も64bitの型に直し、変数への代入が正しいか確かめる

Microsoftは、PtrSafeだけを足した例も示しています。次の宣言は64bit版で通りますが、戻り値(アクティブウィンドウのハンドル)はまだLongです。

Declare PtrSafe Function GetActiveWindow Lib "user32" () As Long

PtrSafeは「この宣言は64bit向けに確認した」という表明にすぎないため、コンパイラは通します。戻り値を受ける型が足りないままなので、ハンドルの上位32bitが落ちる危険が残ります。正しくは次の形です。

Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr

この「宣言は通るが中身が直っていない」状態を機械的に見分けることが、Claude Codeに任せる際の最大の論点になります。

手順1: モジュールを書き出して洗い出す

Claude CodeはExcelを起動できないので、VBEでモジュールを .bas / .cls / .frm として書き出し、テキストを対象にします。書き出し方と文字コードの注意は、先のVBAマクロの記事に書きました。ここでは書き出し済みの src/ を前提にします。

まず、PtrSafeが無いDeclare文をgrepで数えます。Claudeに探させる前に、件数を人が知っておくと、後で「取りこぼしがないか」を比べられます。

# Declare文を持つ行(PtrSafe有無を問わない)
grep -rniE '^\s*((public|private)\s+)?declare\s' src/
 
# PtrSafeが付いていない行だけ
grep -rniE '^\s*((public|private)\s+)?declare\s' src/ | grep -viE 'ptrsafe'

行継続文字(_)でDeclare文を複数行に分けている場合、2行目以降の引数は上のgrepに掛かりません。件数を信用しすぎず、Declareの出現数と、置換後に LongPtr が増えた数を突き合わせる使い方が現実的です。

手順2: 置換のルールをCLAUDE.mdに書く

「Longを全部LongPtrに」と頼むと、ポインタでも何でもない引数まで型が変わります。判断の基準を文章で渡しておきます。公式のメモリ解説では、CLAUDE.mdは「強制される設定」でなくコンテキストとして扱われ、具体的で検証できる書き方のほうが守られやすいとされています。次は、基準をそのまま書いた例です(一例です)。

## VBA 64bit対応ルール
- 対象は src/ 配下の .bas / .cls / .frm。ブック(.xlsm)は編集しない
- Declare文には PtrSafe を付ける。形は Declare PtrSafe Function ...
- ポインタ・ハンドルを受ける引数と戻り値は LongPtr にする
- 64bit整数を入れる値は LongLong にする(64bit版でのみ有効)
- ポインタ・ハンドルでない引数(フラグ、サイズ等)は Long のまま変えない
- 型を変えた宣言ごとに、変更理由を1行のコメントで残さず、報告に書く
- 旧版Office(VBA6)でも開く必要がある場合は #If VBA7 Then で分岐する

VBA専用の指示を .claude/rules/ に切り出し、paths で src/**/*.bas などに絞ることもできます。該当ファイルを読み書きしたときだけ、その規則がコンテキストに載る仕組みです。

手順3: 依頼は「分類してから直す」の2段階にする

最初の依頼は、直すのではなく一覧にさせます。

src/ の Declare 文をすべて列挙して、次の表にして。まだ編集しないで。
ファイル / 行 / 関数名 / ライブラリ / 引数と戻り値の型 / ポインタ・ハンドルの疑い

一覧が出たら、人が目で確かめます。ライブラリ名(user32、kernel32 など)と関数名から、引数がハンドルなのか数値なのかが読み取れる行も多いですが、判断が割れる引数は一覧のまま人が決めます。確認が済んだ行だけを、次の依頼で直させます。

上の表で「ポインタ・ハンドル」と確定した引数だけ LongPtr に変えて。
全 Declare 文に PtrSafe を付けて。変更した宣言を差分で見せて。

先に一覧を取る理由は、Declare文の本数が数十を超えると、一度に直した結果の見落としを人が追えなくなるためです。1ファイルずつ区切る進め方でもかまいません。

手順4: 呼び出し側とUDTを追う

Declare文を直しても、呼び出す側の変数が Long のままなら、戻り値を受けた時点で値が切り捨てられます。次の依頼で、宣言の外を洗います。

Declare で宣言した関数の戻り値を受けている変数と、引数に渡している変数を
全部探して。型が Long のものを、LongPtr にすべきか理由つきで一覧にして。
Type ... End Type のうち、ハンドルやポインタを含むものも挙げて。

LongLongは、64bit版でのみ宣言できる型です。32bit版Officeでも開かれるブックでLongLongを直に書くと、そちらで動かなくなります。両対応が必要なら、ポインタとハンドルはLongPtrで受け、64bit固有の処理だけを #If Win64 Then で囲みます。Microsoftのドキュメントでは、VBA7かどうかを VBA7、64bitかどうかを Win64 という条件付きコンパイル定数で判別します。

#If VBA7 Then
    Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
    Declare Function GetActiveWindow Lib "user32" () As Long
#End If

VBA6以前の環境を考える必要がなければ、この分岐は要りません。Declare PtrSafe自体が、32bit・64bit両方のVBA7で動く書き方です。

手順5: 置換漏れをフックで止める

Claudeが .bas を書き換えた直後に、PtrSafeの無いDeclareが残っていないかを自動で調べておくと、見落としに気づけます。PostToolUse に Edit|Write のマッチャーを付ける設定は公式にあり、編集のたびにコマンドが走ります。ただし Bash コマンドなどによる書き換えではこのフックは動かないと公式に書かれているため、最終確認は手順1のgrepで行います。

#!/bin/bash
# .claude/hooks/check-ptrsafe.sh(一例)
f=$(jq -r '.tool_input.file_path' < /dev/stdin)
case "$f" in
  *.bas|*.cls|*.frm)
    if grep -niE '^\s*((public|private)\s+)?declare\s' "$f" \
        | grep -viE 'ptrsafe'; then
      echo "PtrSafe の無い Declare 文があります: $f" >&2
      exit 2
    fi ;;
esac

終了コード2で返すと、標準エラー出力の内容がClaudeに戻ります。この仕組みで、Declare文の見落としは再作業の指示としてフィードバックされます。

手順6: 64bit版Officeで動かして検証する

文字列検査で確かめられるのは、PtrSafeの有無までです。型の正しさは、64bit版のExcelで確かめます。

  1. 書き出したモジュールをVBEに取り込み、プロジェクトをコンパイルする。Declare文のエラーはこの段階で出る
  2. API呼び出しを含むプロシージャをステップ実行し、戻り値がゼロや負数になっていないか確かめる
  3. 戻り値の変数をウォッチ式で見て、型がLongPtr(64bit環境ではLongLong)になっているかを確かめる
  4. エラーや想定外の値をClaude Codeに貼り戻し、該当する宣言と呼び出しだけを直させる

型を切り詰める事故は、小さな値では表に出にくい点が厄介です。ハンドルの値が小さい間は動いてしまうので、実運用に近いブックでの確認が要ります。

型を変えたあとに止まる箇所

LongPtrを導入すると、別の場所でコンパイルエラーが出ることがあります。64bit版でLongPtrはLongLongに解決され、LongLongを小さい整数型へ暗黙に代入することは認められていないためです。ポインタの切り捨てを防ぐための仕様で、エラーが出た箇所は、まさに切り捨てが起き得た代入です。直し方は2通りあります。受ける側の変数もLongPtrにするか、値が小さいと確かな場合に限って変換関数で明示的に変換するかです。Microsoftは変換関数としてCLngPtr(LongPtrへ)とCLngLng(LongLongへ。64bit版のみ)を用意しています。

Claude Codeに「コンパイルエラーを消して」とだけ頼むと、手近なところに明示変換を足して済ませる直し方も考えられます。エラーが消えても、切り捨ての危険は残ります。次のように、直し方の優先順位を指定しておくのが安全です。

LongLong から Long への代入でエラーが出た箇所は、まず受ける変数を
LongPtr に変える案を出して。CLng などで型を切り詰める案は、
値の範囲が保証できる根拠を添えたときだけ出して。

なお、変数の既定の型を範囲指定で決めるDefType文にも、LongPtrとLongLong用のDefLngPtr、DefLngLngが加わっています。古いモジュールの先頭にDefLng系の宣言が残っていないかも、grepで見ておくと取りこぼしを減らせます。

変更を差分で追えるようにする

Declare文の一括置換は、1行ごとの変更が小さい分、全体では見落としが紛れ込みます。作業の前に書き出したモジュールをGitにコミットしておき、Claude Codeの編集後に差分を読む運用にします。見るのは3点です。

  • 変わった行がDeclare文の行か、その呼び出し側に限られているか
  • Lib のライブラリ名や Alias の関数名が書き換わっていないか
  • 引数の ByVal / ByRef の指定が消えていないか

AliasはDLL側の名前が違うときに使う句で、# で始めると序数での指定になります。型の置換のついでにこの文字列を整形されると、別の関数を呼ぶことになりかねません。CLAUDE.mdの規則に「Lib・Alias・ByVal・ByRefは変更しない」と一行足しておくと、依頼のたびに繰り返さずに済みます。

Claude Codeに任せる範囲と、人が見る範囲

作業任せ方
Declare文の列挙、PtrSafeの付与任せ方任せやすい。件数を人が先に数えておく
引数がポインタかどうかの判定任せ方一覧を人が確認してから確定させる
呼び出し側の変数の型任せ方洗い出しを任せ、変更は人が理由を見て承認
動作確認任せ方64bit版Officeを持つ人が行う。Claude Codeは実行できない

Declare文の移行は、変更箇所が文字列として拾いやすい点で、Claude Codeと相性の良い部類です。一方で、判断の要る箇所は引数の意味づけに集まっています。そこを人の確認に回す分業にしておけば、一括置換の速さを失わずに済みます。

古い資産を機械的に直せる部分と判断が要る部分に分ける進め方は、Struts 1.xのAction・JSP対応表づくりでも同じ形になります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. learn.microsoft.com/en-us/office/vba/language/concepts/getting-started/64-bit-…
  2. learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/de…
  3. code.claude.com/docs/en/memory
  4. code.claude.com/docs/en/hooks
この記事を共有:XはてブLinkedIn