AutoCAD API を使ったアドオン アプリケーションの移植性 の記事では、AutoCAD API の移植性についてご案内しました。その際、AutoCAD 上で VBA を使った場合、パフォーマンスや互換性に不具合が生じてしまうことをご説明しました。
念のため、そのポストを抜粋してここに記載しておきましょう。
なお、AutoCAD 2009 以前で VBA プロジェクトを利用していた方は、AutoCAD 2010 以降の VBA 環境に注意してください。VBA コンポーネントは、AutoCAD 2010 から インストールメディア(DVD-ROM) には含まれず、http://www.autodesk.com/vba-download からのダウンロード提供に切り替わっています。これは、Microsoft 社が提供する VBA コンポーネントが、32 ビット版でしか用意されていないためです。
64 ビット版 Windows 上で動作する 64 ビット版 AutoCAD で、32 ビット版 VBA を動作させるには、プログラムの実行時に AutoCAD と VBA の内部的な通信が発生します。32 ビット版 Windows 上で動作する 32 ビット版 AutoCAD の場合には、同じ 32 ビット版 VBA は AutoCAD と同じメモリ空間で動作することが出来るので、この通信が発生しないのです。この結果、 64 ビット版 AutoCAD で VBA を実行すると、パフォーマンスが低下したり、一部の VBA プログラムの互換性が崩れることになってしまいました。

今日は、32 ビットと 64 ビットのプラットフォーム差で、AutoCAD VBA の実行にどうった問題が発生するか、具体的に紹介しておきましょう。
パフォーマンス差
ここでは、モデル空間の原点を中心に、放射線状に線分を作図する簡単なプログラムで、パフォーマンスの差を実感してみましょう。仕様するプログラムは、次のコードです。
Public Sub PerformanceCheck()
Dim strStart As Variant
strStart = Timer
Dim ptStart(0 To 2) As Double
Dim ptEnd As Variant
ptStart(0) = 0#: ptStart(1) = 0#: ptStart(2) = 0#
Dim i As Double
For i = 0# To 360# Step 0.1
ptEnd = ThisDrawing.Utility.PolarPoint(ptStart, i, 100#)
Call ThisDrawing.ModelSpace.AddLine(ptStart, ptEnd)
Next i
ThisDrawing.Utility.Prompt vbCrLf & “経過時間は …” & Timer – strStart & “秒” & vbCrLf
End Sub
AutoCAD のインストーラは、AutoCAD をインストールしようとする Windows プラットフォームにビット数に合わせて、同じビット数の AutoCAD をインストールするようになっています。先にご紹介しているように、VBA コンポーネントだけが、32 ビット版しか存在しないことに注意してください。それでは、この VBA マクロを 次の環境でテストしてみます。
- Windows 7 32 ビット版+AutoCAD 2013 32 ビット版+VBA 32 ビット版
- Windows 7 64 ビット版+AutoCAD 2013 64 ビット版+VBA 32 ビット版
Windows では、異なるビット数を同じプロセス内で一緒に動作させることが出来ないため、AutoCAD 64 ビット版と VBA 32 ビット版の各プロセス間を、プロセス間通信で補っているためです。このプロセス間通信をしているコンポーネントが、AutoCAD 2013 の場合 x64VBAServer19.exe で、AutoCAD 本体の acad.exe と通信しながら VBA マクロを実行しているため、全体のパフォーマンスが低下した結果に表れます。
32 ビット版 Windows に場合には、AutoCAD と VBA がどちらも 32 ビット版となるため、AutoCAD のプロセス内で VBA を動作させることができます。このため、プロセス間通信は発生しないので、高速に VBA マクロを実行することができるのです。
VBA マクロ プログラムの互換性
もう 1 つ、ここでは、64 ビット環境に移植できない VBA マクロのプログラム例をご紹介します。
Public Sub Main()
‘ 新しい表スタイルの作成
On Error Resume Next
Dim oTblDict As AcadDictionary
Set oTblDict = ThisDrawing.Dictionaries.Item(“ACAD_TABLESTYLE”)
Dim oTblStyle As AcadTableStyle
Set oTblStyle = oTblDict.Item(“MyTableStyle”)
If Err Then
‘ 新しい表スタイル “MyTableStyle” を作成
Err.Clear
Set oTblStyle = oTblDict.AddObject(“MyTableStyle”, “AcDbTableStyle”)
‘ タイトル欄の設定(背景色:青、文字色:白、文字高さ:4.0)
Dim oColor As AcadAcCmColor
Set oColor = AcadApplication.GetInterfaceObject(“AutoCAD.AcCmColor.18”)
Call oColor.SetRGB(255, 255, 255)
oTblStyle.SetColor acTitleRow, oColor
oColor.ColorIndex = acBlue
oTblStyle.SetBackgroundColor acTitleRow, oColor
oTblStyle.SetTextHeight acTitleRow, 4#
oTblStyle.TitleSuppressed = False
‘ 列見出し欄の色設定(背景色:白、文字色:緑、文字高さ:2.5)
oColor.ColorIndex = acWhite
oTblStyle.SetColor acHeaderRow, oColor
oColor.ColorIndex = acGreen
oTblStyle.SetBackgroundColorNone acHeaderRow, False
oTblStyle.SetBackgroundColor acHeaderRow, oColor
oTblStyle.SetTextHeight acHeaderRow, 2.5
oTblStyle.HeaderSuppressed = False
‘ データ欄の色設定(背景色:なし、文字色:白、文字高さ:2.5)
oColor.ColorIndex = acWhite
oTblStyle.SetColor acDataRow, oColor
oTblStyle.SetBackgroundColorNone acDataRow, True
oTblStyle.SetTextHeight acDataRow, 2.5
oTblStyle.SetAlignment acDataRow, acMiddleCenter
End If
On Error GoTo 0
‘ 配置基点を指示
Dim ptBase As Variant
ThisDrawing.Utility.InitializeUserInput 1
ptBase = ThisDrawing.Utility.GetPoint(, vbCrLf & “表の配置点を指定:”)
‘ 表特性の算出
Dim nRow As Integer
Dim nCol As Integer
Dim dHeight As Double
nRow = ThisDrawing.ModelSpace.Count + 2 ‘ タイトル+列見出し
nCol = 3
dHeight = ThisDrawing.GetVariable(“TEXTSIZE”)
‘ 現在のレイアウトに表を配置
Dim oTbl As AcadTable
Set oTbl = ThisDrawing.ActiveLayout.Block.AddTable(ptBase, nRow, nCol, dHeight, dHeight * 10#)
oTbl.RegenerateTableSuppressed = True
oTbl.StyleName = “MyTableStyle”
oTbl.GenerateLayout
‘ タイトルの設定
oTbl.SetText 0, 0, “モデル空間図形の色一覧”
oTbl.SetRowHeight 0, 7#
oTbl.SetText 1, 0, “ハンドル番号”
oTbl.SetText 1, 1, “クラス名”
oTbl.SetText 1, 2, “色”
oTbl.SetRowHeight 1, 5#
‘ データの設定
Dim nRowCnt As Integer
Dim strField As String
Dim oEnt As AcadEntity
For nRowCnt = 2 To ThisDrawing.ModelSpace.Count
‘ モデル空間要素の取得
Set oEnt = ThisDrawing.ModelSpace.Item(nRowCnt – 2)
‘ ハンドル番号
oTbl.SetText nRowCnt, 0, oEnt.Handle
‘ クラス名
oTbl.SetText nRowCnt, 1, oEnt.ObjectName
‘ フィールド式(オブジェクトID で特定したオブジェクトの色)
strField = “%<\AcObjProp Object(%<\_ObjId ” & CStr(oEnt.ObjectID) & “>%).TrueColor>%”
oTbl.SetText nRowCnt, 2, strField
‘ 行高さの設定
oTbl.SetRowHeight nRowCnt, 5#
Next
oTbl.RegenerateTableSuppressed = False
End Sub
この VBA プログラムは、モデル空間に作図されている図形のハンドル番号、色、図形タイプを AutoCAD の表オブジェクトに書き出す処理をしています。色番号の部分では、それぞれの図形の色を フィールド として書き出されている点に注意してください。フィールドは、図面内の特定の情報を監視して、その情報を文字として表示する機能があります。このプログラムでは、モデル空間の図形、1 つ 1 つを監視して、その図形の色を文字として表示しています。

このため、VBA マクロで作図した表の作成後に、参照されている図形の色を変更して、REGEN[再作図] コマンドを実行すると、変更した図形の色が表に自動的に反映されることがわかります(32 ビット プラットフォームのみ)。
そして、この VBA マクロは残念ながら 64 ビット版の AutoCAD では実行時にエラーで正しく動作しません。なぜなら、フィールド文字として図形の色を関連付けるときに、オブジェクト ID と呼ばれる識別子 ObjectID プロパティで利用しているためです。
' フィールド式(オブジェクトID で特定したオブジェクトの色)
strField = "%<\AcObjProp Object(%<\_ObjId " & CStr(oEnt.ObjectID) & ">%).TrueColor>%"
オブジェクトID は、ObjectARX や AutoCAD .NET API を利用されている方にはおなじみの識別子ですが、この識別子は、プラットフォーム依存なので、このような非互換な結果になってしまうのです。
こういったプラットフォーム差を吸収するために、オートデスクでは、VBA マクロを同じ Visual Basic 言語を利用できる AutoCAD .NET API に移植することをお勧めしています。
AutoCAD 2014 と 64 ビット版 VBA
ここに来て、32 ビット版のコンポーネントしかリリースしていなかった Microsoft 社が、64 ビット版のコンポーネントをリリースすることになりました。つまり、64 ビット版の AutoCAD と同じプロセス内で VBA が実行できるようになります。そして、新しくリリースされた AutoCAD 2014 では、64 ビット版の AutoCAD 用に http://www.autodesk.com/vba-download から 64 ビット版の VBA をダウンロード提供しています。残念ながら、AutoCAD 2014(以降)にしか適用することは出来ませんが、これによって、32 ビット版 AutoCAD と 64 ビット版の AutoCAD で、VBA のパフォーマンス差やコードの非互換性も解消できることが期待できます。
ただし、この状況でも、オートデスクは AutoCAD .NET API への移植を推奨している点に注意してください。VBA の言語仕様は、十数年前の Visual Basic 6.0 のままです。VBA が持つ COM との互換性があり、.NET Framework ベースの新しい VB.NET を使うことが可能な AutoCAD .NET API が移植先として最適なのです。
By Toshiaki Isezaki

Leave a Reply