【入門編】【上級】64bit環境におけるAcadApplicationのAPI宣言:PtrSafeとLongPtrの使い分けとメモリ管理 – AutoCAD VBA解析バイブル

スポンサーリンク

こんにちは!AutoCAD VBAの世界へようこそ。
今日は、多くの開発者がレガシーなコードを近代化する際に直面する、避けて通れない「超重要テーマ」についてお話しします。

そう、「64bit環境におけるAPI宣言:PtrSafeとLongPtrの使い分けとメモリ管理」です。

「いきなりAPIとかポインタとか言われても……マクロの記録から抜け出したばかりだし難しそう」と思いましたか?大丈夫です。ここをクリアすれば、あなたのAutoCAD VBAスキルは一気にプロの領域へ到達します。

今日は、技術の本質を噛み砕きながら、現場でそのまま使える実践的な知識を優しく、そして深く伝授していきましょう。ここをクリアすれば、AutoCAD VBAの基礎はバッチリですよ!

1. なぜ64bit化でVBAは「クラッシュ」するのか?

まず、私たちが普段使っているAutoCADとVBAの裏側の話を少しだけさせてください。

昔のパソコンやAutoCADは「32bit版」が主流でした。この時代、メモリ(RAM)の世界は狭く、アドレス(メモリ上の番地)も32bit(4バイト)の整数で管理されていました。VBAのコード内でも、Windowsの裏側の仕組み(Win32 API)を呼び出すときは、すべて「Long型(32bit)」を使ってメモリの場所を指定していたのです。

しかし、現代のPCは64bitが当たり前。AutoCADも当然64bitアプリケーションです。
64bit環境では、メモリのアドレスは64bit(8バイト)の巨大なサイズになります。

ここで何が起きるか?
64bitの巨大なポインタ(メモリ番地)を、昔のままの32bit(Long型)の箱に無理やり詰め込もうとすると……メモリがあふれ、AutoCADごとフリーズ、あるいは一瞬で強制終了(クラッシュ)します。

この悲劇を防ぐために導入されたのが、`PtrSafe``LongPtr` という新しい呪文(キーワード)なのです。

2. 魔法のキーワード:`PtrSafe` と `LongPtr` の正体

64bit版のOfficeやAutoCADでWindows APIを叩くときは、以下の2つのルールを守るだけでエラーを完全に回避できます。

1. `Declare` の後ろに `PtrSafe` をつける

  • 「このAPI宣言は、64bitの世界でも安全に動きますよ」とVBAに宣言します。

2. メモリの住所(ポインタやハンドル)を表す型を `LongPtr` にする

  • 32bit環境では4バイト、64bit環境では8バイトへと、実行環境に合わせて自動的にサイズを変えてくれる賢い型です。

図解:ポインタのサイズ変化

[32bit環境]
LongPtr (または Long) : [ 4バイト (32bit) ] ── Windows APIの住所

[64bit環境]
LongPtr : [ 8バイト (64bit) ] ── Windows APIの住所 (自動拡張!)
※ 従来の Longのままだと、ここでメモリがあふれてクラッシュ!

3. 【実践】AutoCADのウィンドウを操作するAPIコード例

百聞は一見にしかず。実際にAutoCADのメインウィンドウのハンドル(識別番号)を取得し、タイトルバーの文字を書き換えるコードを見てみましょう。

このコードは、64bitのAutoCAD VBA環境(AutoCAD 2021以降など)でそのままコピー&ペーストして動かすことができます。

Option Explicit

‘ ====================================================================
‘ Windows APIの宣言 (64bit/32bit両対応版)
‘ ====================================================================
If VBA7 Then
‘ — Office 2010 / AutoCAD 2011以降の64bit/32bit共通環境 —
‘ PtrSafeを付与し、ハンドルやポインタをLongPtrに変更しています
Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String _
) As LongPtr

Declare PtrSafe Function SetWindowText Lib “user32” Alias “SetWindowTextA” ( _
ByVal hwnd As LongPtr, _
ByVal lpString As String _
) As Long
Else
‘ — 古いレガシー環境(32bit専用) —
Declare Function FindWindow Lib “user32” Alias “FindWindowA” ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String _
) As Long

Declare Function SetWindowText Lib “user32” Alias “SetWindowTextA” ( _
ByVal hwnd As Long, _
ByVal lpString As String _
) As Long
End If

‘ ====================================================================
‘ メインプロシージャ:AutoCADのタイトルを変更する
‘ ====================================================================
Sub ChangeAutoCADTitle()
Dim hCadWnd As LongPtr
Dim originalTitle As String

‘ 1. 現在アクティブなAutoCADのメインウィンドウのハンドルを取得
‘ AutoCADのクラス名は通常 “AutoCAD” ですが、バージョンにより異なります
‘ ここでは現在開いているドキュメントのタイトルをキーにウィンドウを探します
Dim docName As String
docName = ThisDrawing.Name

hCadWnd = FindWindow(vbNullString, docName & ” – AutoCAD”)

‘ ウィンドウが見つかったかチェック
If hCadWnd = 0 Then
MsgBox “対象のAutoCADウィンドウが見つかりませんでした。”, vbExclamation
Exit Sub
End If

‘ 2. ウィンドウのタイトルを書き換える
Dim success As Long
success = SetWindowText(hCadWnd, “【超最高峰の自動化稼働中】 ” & docName)

If success <> 0 Then
MsgBox “API呼び出し成功:タイトルを書き換えました!”, vbInformation

‘ 3秒待って元に戻す(実務では不要ですがデモ用です)
Application.Wait (Now + TimeValue(“00:00:03″))
SetWindowText hCadWnd, docName & ” – AutoCAD”
Else
MsgBox “タイトルの変更に失敗しました。”, vbCritical
End If

End Sub

コードの解説とポイント

  • `#If VBA7 Then` 構文の魔術

VBAのバージョン(VBA7以降かどうか)を判定し、64bit対応の構文と古い32bit専用の構文を自動で切り替えています。これにより、古いコード資産を壊さずに現代の64bit環境へ移行できます。

  • `LongPtr` の使用

ウィンドウハンドル (`hwnd`) を格納する変数 `hCadWnd` には必ず `LongPtr` を使います。ここを `Long` にしてしまうと、64bit環境でメモリバスエラーを引き起こします。

4. 陥りやすいエラーとメモリリークの罠

APIを扱う上で、もう一つ絶対に知っておかなければならないのが「メモリ管理」です。

VBAは非常に優れたガベージコレクション(不要になったメモリの自動解放)を持っていますが、Windows APIを通じて外部から確保したメモリや、ポインタを直接操作して取得したリソースは、VBAの管理外になります。

よくある失敗例:

  • APIでメモリ領域(グローバルヒープなど)を確保したのに、処理が終わったあとに `GlobalFree` などの解放APIを呼び忘れる。
  • ループ処理の中で何度もウィンドウやデバイスコンテキスト(DC)のハンドルを取得し、解放せずに放置する。

これらを繰り返すと、AutoCADが徐々にメモリを食いつぶし、最終的に「メモリ不足(Out of Memory)」でフリーズします。巨大な図面を扱うAutoCADにおいて、メモリリークは致命傷です。

黄金の鉄則:

1. 「取得したら必ず解放する」(リソースのペアを崩さない)。
2.エラー発生時(`On Error GoTo`)でも確実に解放処理を通るようなクリーンアップコードを書く。

Sub SafeApiUsageSample()
On Error GoTo ErrorHandler

‘ 【リソース取得】
‘ Dim hMemory As LongPtr
‘ hMemory = GlobalAlloc(…) などの処理

‘ 処理本体…

‘ 【正常終了時の解放】
‘ GlobalFree(hMemory)
Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました。クリーンアップを実行します。”, vbCritical
‘ 【異常終了時の解放】
‘ GlobalFree(hMemory)
End Sub

最後に:基盤を固めて、真のAutoCAD自動化マスターへ

今回は、64bit環境におけるAPI宣言の極意と、メモリ管理の基本について深く掘り下げました。

  • `PtrSafe` と `LongPtr` で64bitのメモリ構造にアジャストする。
  • `#If VBA7 Then` でバージョンの違いをスマートに吸収する。
  • 外部リソースは必ず自分で管理・解放する。

この3つさえ押さえておけば、どれほど巨大で複雑なWindows API連携システムであっても、恐れることはありません。

「ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ!」
ぜひ、あなたの開発環境でもこの知識を活かして、より堅牢でプロフェッショナルなマクロ・アドインを作り上げてください。次回の解説もお楽しみに!

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