SolidWorks VBAの「闇」を制する:UserFormによるUI構築とメモリ管理の極意
VBAはレガシーではない。使い手次第で、それはCADの操作性を極限まで高める「究極のインターフェース」へと昇華する。
多くのエンジニアが黒いVBAエディタから脱却できず、デバッグウィンドウを眺めて時間を浪費している間に、我々はUserFormを駆使し、SolidWorksの操作レイヤーを再定義する。本稿では、単なるフォーム作成ではなく、メモリの深淵を制御し、堅牢なシステムを構築するための「伝説的アーキテクチャ」を伝授する。
—
1. UserFormの「非モーダル」制御とSolidWorksの共存
UserFormのデフォルトはモーダル(他の操作をブロックする)だが、CAD操作中にこれが許されることはない。設計者はフォームを表示したまま、モデル上の面やエッジを選択し、マクロにデータを引き渡す必要がある。
極限の知見:VB6/VBAにおけるAPIの非同期操作
フォームを表示する際、`Show vbModeless`を使用するのは当然の初手だ。しかし、これだけではSolidWorksの再描画プロセスと干渉し、クラッシュを誘発する。ここで重要になるのが、`DoEvents`の適切なハンドリングと、Windows APIによるウィンドウハンドル(hWnd)の制御だ。
‘ UserFormの初期化時にSolidWorksのウィンドウを親として固定する(API連携)
If VBA7 Then
Private Declare PtrSafe Function SetWindowLong Lib “user32” Alias “SetWindowLongPtrA” (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
Private Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Else
‘ 32bit環境への配慮(レガシー保守の教訓)
End If
Private Sub UserForm_Initialize()
‘ SolidWorksのメインウィンドウを親プロセスとして取得し、フォームを従属させる
‘ これにより、Alt+Tabでの切り替えや最小化の挙動が安定する
Dim swHwnd As LongPtr
swHwnd = Application.SldWorks.FrameWindowHandle
SetWindowLong Me.hWnd, -8, swHwnd
End Sub
—
2. オブジェクトのライフサイクルとメモリ解放の真実
VBAはガベージコレクションを搭載していない。あなたが`Set swModel = Nothing`を書き忘れるたびに、SolidWorksのメモリ使用量は肥大化し、数時間後には「SolidWorksの動作が重い」という現場の悲鳴となって跳ね返ってくる。
メモリリークを撲滅する「Disposeパターン」
VBAにDisposeメソッドは存在しないが、設計思想として取り入れることは可能だ。
- 循環参照の回避: クラスモジュール内で`SldWorks`オブジェクトを保持し続けると、終了時にメモリが解放されない。
- 明示的なリセット: フォームを閉じる際は、必ず全てのグローバル変数、オブジェクト変数を解放する。
Public Sub TerminateTool()
‘ オブジェクトの連鎖を断ち切るのがアーキテクトの矜持
Set swModel = Nothing
Set swApp = Nothing
Unload Me
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
‘ ユーザーが×ボタンを押しても確実にクリーンアップする
If CloseMode = vbFormControlMenu Then
Call TerminateTool
End If
End Sub
—
3. モデル選択の「コールバック」アーキテクチャ
UIからモデルを選択する際、`swModel.SelectionManager`をループさせるような低効率なコードを書いてはならない。現場のエンジニアは待たされることを最も嫌う。
真のエンジニアは、イベントハンドラ(Class Module)を使用して、SolidWorks側からの「選択」通知をトリガーにする。
賢者の実装:イベントによるリアルタイムUI更新
‘ Class Module: clsSwEvents
Public WithEvents swApp As SldWorks.SldWorks
Public WithEvents swModel As SldWorks.ModelDoc2
Private Function swModel_UserSelectionPostNotify() As Long
‘ 選択が変わった瞬間にフォーム上のラベルを即座に更新する
‘ 重い処理は行わず、データの取得と表示のみに特化させる
Dim selMgr As SldWorks.SelectionMgr
Set selMgr = swModel.SelectionManager
UserForm1.lblSelectedCount.Caption = “選択数: ” & selMgr.GetSelectedObjectCount2(-1)
End Function
このイベント駆動設計により、ポーリング(常時監視)によるCPU負荷をゼロに抑え、SolidWorksのパフォーマンスを一切損なわない操作パネルが実現する。
—
4. 最後に:なぜ「VBA」なのか
最新のC# / .NET APIの方がモダンであることは否定しない。しかし、VBAには「配布の容易さ」と「実行環境のミニマリズム」がある。SolidWorksがインストールされているPCであれば、追加のランタイムなしで、即座に現場の課題を解決できる。
この記事を読んでいる君たちへ。
コードの美しさは、メモリの細部への配慮と、ユーザー(現場の設計者)のストレスをどれだけ排除できたかに宿る。
「動けばいい」という考えは、エンジニアではなくオペレーターの思考だ。
次は、このフォームを社内データベースと連携させ、パラメータの自動生成まで組み込む設計を考えてみてほしい。SolidWorks APIの可能性は、まだ君たちの想像の先にある。
