VBAマクロの限界を超え、SolidWorks Add-in(COMコンポーネント)へ昇華させる手法
長年SolidWorks VBAと向き合ってきた者なら、誰もが一度は「あのマクロをもっと洗練させたい」「SolidWorks起動時から自動で動いてほしい」「他のシステムとの連携をスムーズにしたい」と考えたことがあるはずだ。VBAマクロは手軽で強力だが、その実行タイミング、常駐性、そしてCOMオブジェクトとしての振る舞いには、どうしても限界がある。
本稿では、そんなVBAマクロの限界を打ち破り、真のSolidWorks Add-in、すなわちCOMコンポーネントとして昇華させるためのステップを、経験に基づいた「極限の知見」と共に解説する。単なるAPIリファレンスの羅列ではない。オブジェクトのライフサイクル、メモリ管理、そしてレガシーシステムとの共存という、現場の最前線で戦ってきた者だけが語れる真髄を、ここに記す。
1. VBAマクロからAdd-inへの移行:なぜCOMコンポーネントなのか?
VBAマクロは、SolidWorksのアプリケーション内で実行されるスクリプト言語であり、その実行はユーザーのアクションに依存する。一方、SolidWorks Add-inは、COM(Component Object Model)という共通のインターフェース規格に基づいた、独立したアプリケーションコンポーネントである。
このCOMコンポーネント化がもたらすメリットは計り知れない。
- 常駐性: SolidWorks起動時に自動的にロードされ、常駐してユーザーの操作を監視したり、バックグラウンドで処理を実行したりできる。
- イベント駆動: SolidWorksの様々なイベント(ドキュメントを開く、部品を挿入するなど)を捉えて、自動的に処理を実行できる。
- リボンメニューへの統合: 独自のボタンやタブをリボンメニューに配置し、ユーザーインターフェースを大幅に拡張できる。
- パフォーマンス: COMコンポーネントは、一般的にVBAマクロよりも効率的なメモリ管理と高速な処理が可能。
- システム間連携: 他のCOM対応アプリケーションや、Windows APIを直接呼び出すことで、より高度なシステム連携を実現できる。
特に、「システム間連携」と「レガシー環境の保守」という観点からは、COMコンポーネント化は避けて通れない道である。古くから存在する基幹システムがCOMベースで構築されている場合、VBAマクロではその連携が困難、あるいは非効率になるケースが多々ある。Add-inとしてCOMコンポーネント化することで、これらのレガシーシステムとSolidWorksをシームレスに連携させ、既存資産を最大限に活用できるのだ。
2. Add-in開発の準備:VB.NETとVisual Studioの活用
Add-in開発には、VB.NETとVisual Studio(Community Editionでも十分)の使用を強く推奨する。VBAマクロの構文に慣れていても、COMコンポーネントの登録、メモリ管理、そしてより複雑なAPIの利用には、VB.NETの方が圧倒的に効率的で、安全な開発が可能となる。
2.1. プロジェクトの作成
1. Visual Studioを起動し、「新しいプロジェクトの作成」を選択。
2. 「クラスライブラリ (.NET Framework)」テンプレートを選択。(注意:.NET Coreや.NET 5以降ではなく、.NET Frameworkを選択してください。SolidWorks APIは.NET Frameworkとの互換性が高いです。)
3. プロジェクト名(例: `SolidWorksAddinExample`)と場所を設定し、「作成」をクリック。
2.2. SolidWorksへの参照設定
Add-inとしてSolidWorksのAPIを利用するためには、SolidWorksのCOMライブラリへの参照設定が必要となる。
1. ソリューションエクスプローラーで、プロジェクトを右クリックし、「参照の追加」を選択。
2. 「COM」タブを選択し、リストの中から「SolidWorks <バージョン> Type Library」を探してチェックを入れる。(例: `SolidWorks 2023 Type Library`)
3. 必要に応じて、`SWConst`(SolidWorks定数ライブラリ)なども追加する。
4. 「OK」をクリック。
2.3. COM Visibleの設定
作成するクラスライブラリがCOMコンポーネントとして認識されるためには、いくつかのアセンブリレベルの設定が必要となる。
`My Project` (プロジェクト名を右クリックし、「プロパティ」を選択)を開き、以下の設定を行う。
- Compile タブ:
- 「Register for COM interop」にチェックを入れる。
- Application タブ:
- 「Assembly name」を、COM登録時に使用される名前(例: `SolidWorksAddinExample`)に設定する。
- 「Root namespace」も同様に設定する。
また、COM Visibleにするための属性を、`AssemblyInfo.vb` ファイル(プロジェクトのプロパティで開ける)に追記する。
.net
‘ AssemblyInfo.vb
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
‘ General Information about an assembly is controlled through the following
‘ set of attributes. Change these attribute values to modify the information
‘ associated with an assembly.
‘ Review the values of the assembly attributes
‘To be able to use the following types in COM:
`Guid`は、プロジェクト生成時に自動的に付与される。このGUIDは、COMオブジェクトを一意に識別するために非常に重要であり、変更しないように注意が必要だ。
3. SolidWorks Add-inの基本構造:`ISldWorks`と`IAddIn`インターフェース
Add-inとして機能するためには、`SldWorks`アプリケーションオブジェクトを取得し、SolidWorksのAdd-inインターフェースを実装する必要がある。
3.1. `ISldWorks` オブジェクトの取得
Add-inがロードされると、SolidWorksはアプリケーションオブジェクトへの参照を渡してくれる。これは、VBAマクロで `Set swApp = Application.SldWorks` としているのと同様の概念だが、Add-inではその参照が直接引数として渡される。
3.2. `IAddIn` インターフェースの実装
COMコンポーネントとしてSolidWorksに認識されるためには、`ISwAddin`インターフェースを実装したクラスを作成する必要がある。このインターフェースには、Add-inのライフサイクルを管理するためのメソッドが含まれている。
.net
‘ SolidWorksAddin.vb (新しいクラスファイルを作成)
Imports SolidWorks.Interop.sldworks
Imports SolidWorks.Interop.swconst
Imports System.Runtime.InteropServices
‘ COMVisible属性はクラスにも適用する ”’ SolidWorks アプリケーションオブジェクトへの参照。
”’ Add-in を識別するための Cookie。
”’ 登録データ (通常は使用しません)。
”’ ‘ ここでリボンメニューへのボタン追加などの初期化処理を行います。 ”’ ”’ ‘ ここでリソースの解放などのクリーンアップ処理を行います。 ‘ UI要素の削除などもここで行うと良いでしょう。 Return True ‘ — カスタムメソッド — ”’ Private Sub AddRibbonButton() ‘ 例: Add-in を登録する際、SolidWorks は Add-in の Cookie を渡します。 ‘ TODO: RibbonManager を使用したボタン追加処理を実装 ‘ TODO: ボタンがクリックされたときに実行されるメソッドなどを追加 End Class 重要なポイント: VBAマクロで `Set obj = Nothing` としていたように、COMオブジェクトは明示的に解放することがメモリリークを防ぐ上で極めて重要です。特に、`SldWorks` アプリケーションオブジェクトのような、アプリケーション全体に影響を与えるオブジェクトは、Add-in の終了時に確実に解放する必要があります。 `Marshal.ReleaseComObject(obj)` は、COMオブジェクトの参照カウントをデクリメントします。参照カウントがゼロになった時点で、COMオブジェクトはアンロードされ、メモリが解放されます。 `Guid` はCOMコンポーネントの「指紋」のようなものです。プロジェクト作成時に自動生成されるものですが、コピー&ペーストで誤って変更してしまうと、COM登録が失敗したり、意図しないコンポーネントが呼び出されたりする原因になります。常に注意深く管理してください。 Add-in の最も一般的な機能の一つは、リボンメニューにカスタムボタンを追加し、ユーザーがそれをクリックすることで独自の機能を実行できるようにすることです。 SolidWorks API は、リボンメニューを操作するための `RibbonManager` クラスを提供しています。このクラスを使用すると、タブ、パネル、ボタンなどを動的に追加・削除できます。 .net Imports SolidWorks.Interop.sldworks ‘ … (省略) … Public Class SolidWorksAddin Private swApp As SldWorks ‘ UI要素を管理するためのクラス (例) ‘ … (省略) … Public Function OnStartup(ByVal ThisApplication As Object, ByVal Cookie As Integer, ByVal RegistrationData As Object) As Boolean Implements ISwAddin.OnStartup Try ‘ リボンメニューにボタンを追加 Public Function OnShutdown() As Boolean Implements ISwAddin.OnShutdown ‘ UI要素を削除 (リソース解放の前に) ‘ SldWorks オブジェクトを解放 Return True Private Sub AddRibbonButton() ‘ リボンマネージャーを使用してボタンを追加 ‘ ボタンにツールチップを設定 ‘ TODO: 必要に応じてアイコン画像などを設定 ‘ CommandManager がコマンドを処理するためのメソッド Try Dim swModel As ModelDoc2 = DirectCast(swApp.ActiveDoc, ModelDoc2) ‘ 例: カスタムプロパティを設定する MessageBox.Show(“Custom property ‘MyCustomProperty’ set successfully!”, “Success”, MessageBoxButtons.OK, MessageBoxIcon.Information) Catch ex As Exception End Class `RibbonManager` の利用における注意点: Add-in開発では、SolidWorks API のみならず、Windows API を直接呼び出すことで、より低レベルで強力な機能を実現できる場合があります。また、パフォーマンスと安定性を確保するためには、メモリ管理とオブジェクトのライフサイクル管理が不可欠です。 Windows API をVB.NETから呼び出すには、`Declare` ステートメントを使用します。 .net ‘ Declare statement for Windows API functions ‘ 例: プロセスの実行 ‘ MessageBox の定数 (例) Add-in 内でこれらの API を呼び出す例: .net ‘ MessageBox を表示する例 ‘ 外部プログラムを実行する例 (Notepad を起動) 注意点: Add-in は SolidWorks と同時に起動・終了するため、メモリリークは SolidWorks 全体のパフォーマンス低下やクラッシュを引き起こす可能性があります。 Add-in は、長期間にわたって保守されることが想定されます。そのため、以下の点を考慮する必要があります。 Add-in の真価は、SolidWorks と外部システムとの連携において発揮されます。 システム間連携における「極限の知見」: SolidWorks VBA マクロを COM コンポーネントとしての Add-in へと昇華させることは、単なる機能拡張に留まらず、SolidWorks をより強力で統合されたエンジニアリングプラットフォームへと進化させるための重要なステップです。 本稿で解説した、VB.NET による開発、COM の基本、UI 操作、Windows API の活用、そしてメモリ管理とシステム間連携の知見は、Add-in 開発の基盤となります。これらの知識を深め、実践に活かすことで、あなたの SolidWorks 環境は、より自動化され、効率的で、そして洗練されたものへと変貌を遂げることでしょう。 レガシーシステムとの共存、そして将来のシステム連携を見据えたとき、COM Add-in は依然として強力な選択肢であり、その開発スキルは、エンジニアとしての市場価値を大きく高めるはずです。 さあ、あなたの VBA マクロに、COM という魂を吹き込み、真の Add-in へと昇華させる旅を始めましょう。
”’
Public Function OnStartup(ByVal ThisApplication As Object, ByVal Cookie As Integer, ByVal RegistrationData As Object) As Boolean Implements ISwAddin.OnStartup
swApp = DirectCast(ThisApplication, SldWorks)
Console.WriteLine(“SolidWorksAddin: OnStartup called.”)
Try
‘ 例: リボンメニューにボタンを追加する処理
AddRibbonButton()
Console.WriteLine(“SolidWorksAddin: Ribbon button added.”)
Return True
Catch ex As Exception
Console.WriteLine($”SolidWorksAddin: Error in OnStartup: {ex.Message}”)
Return False
End Try
End Function
”’
Public Function OnShutdown() As Boolean Implements ISwAddin.OnShutdown
Console.WriteLine(“SolidWorksAddin: OnShutdown called.”)
‘ オブジェクトの明示的な解放は、メモリリークを防ぐために非常に重要です。
If swApp IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(swApp)
swApp = Nothing
End If
‘ 例: RibbonManager.RemoveButton(…)
End Function
”’ 実際の実装は、Add-in の UI 設計によります。
”’
‘ UIを操作するためのAPI呼び出し
‘ 例: SolidWorksのUIオブジェクトを取得し、ボタンを追加
‘ この部分は、Add-inのUI管理クラスに切り出すのが一般的です。
‘ ここでは簡略化しています。
‘ この Cookie を使用して、Add-in の UI 要素を管理します。
‘ 具体的な UI 操作は、SolidWorks API の UserInterface クラスなどを使用します。
‘ 例:
‘ Dim ribbonManager As RibbonManager = New RibbonManager(swApp, Cookie)
‘ ribbonManager.AddButton(“MyCustomTab”, “MyPanel”, “MyButton”, “RunMyMacro”, Me)
End Sub
3.3. オブジェクトの明示的解放 (`Marshal.ReleaseComObject`)
3.4. GUIDの管理
4. リボンメニューへのボタン追加
4.1. RibbonManager を使用した UI 操作
‘ SolidWorksAddin.vb (上記クラスに追加)
Imports SolidWorks.Interop.swconst
Imports System.Runtime.InteropServices
Imports SolidWorks.Application.UI ‘ UI操作のための名前空間
Implements ISwAddin
Private myCookie As Integer ‘ OnStartup から渡される Cookie を保持
Private ribbonManager As RibbonManager
swApp = DirectCast(ThisApplication, SldWorks)
myCookie = Cookie ‘ Cookie を保持
Console.WriteLine(“SolidWorksAddin: OnStartup called.”)
‘ RibbonManager を初期化
ribbonManager = New RibbonManager(swApp, myCookie)
AddRibbonButton()
Console.WriteLine(“SolidWorksAddin: Ribbon button added.”)
Return True
Catch ex As Exception
Console.WriteLine($”SolidWorksAddin: Error in OnStartup: {ex.Message}”)
Return False
End Try
End Function
Console.WriteLine(“SolidWorksAddin: OnShutdown called.”)
If ribbonManager IsNot Nothing Then
Try
‘ 追加したボタンを削除
ribbonManager.RemoveButton(“MyCustomTab”, “MyPanel”, “RunMyMacroButton”)
Console.WriteLine(“SolidWorksAddin: Ribbon button removed.”)
Catch ex As Exception
Console.WriteLine($”SolidWorksAddin: Error removing ribbon button: {ex.Message}”)
End Try
ribbonManager = Nothing ‘ RibbonManager オブジェクトも解放
End If
If swApp IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(swApp)
swApp = Nothing
End If
End Function
‘ 新しいタブ、パネル、ボタンを定義
Dim tabText As String = “Custom Tools”
Dim panelText As String = “Macros”
Dim buttonText As String = “Run My Macro”
Dim buttonCommand As String = “RunMyMacro” ‘ コマンド名 (CommandManager のイベントで受け取る)
Dim buttonTooltip As String = “Click to run the custom macro”
‘ AddButton(TabText, PanelText, ButtonText, CommandName, ParentObject)
‘ ParentObject は、ボタンがクリックされたときに呼び出されるメソッドを持つオブジェクト
ribbonManager.AddButton(tabText, panelText, buttonText, buttonCommand, Me)
ribbonManager.SetButtonToolTip(buttonCommand, buttonTooltip)
End Sub
‘ このメソッドは、AddButton の ParentObject に指定されたオブジェクト(ここでは Me、つまり SolidWorksAddin クラスのインスタンス)に存在する必要があります。
‘ コマンド名は AddButton で指定したものと一致させる必要があります。
Public Sub RunMyMacro()
Console.WriteLine(“RunMyMacro command executed!”)
‘ ここに、VBAマクロで実行していた処理を記述します。
‘ 例: ドキュメントを取得し、何らかの処理を行う
If swApp Is Nothing Then
MessageBox.Show(“SolidWorks application object is not available.”, “Error”, MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
If swModel Is Nothing Then
MessageBox.Show(“Please open a document first.”, “Information”, MessageBoxButtons.OK, MessageBoxIcon.Information)
Return
End If
swModel.Extension.CustomPropertyManager(“”).Add3(“MyCustomProperty”, swCustomPropertyType_e.swCustomPropertyText, “Hello from Add-in!”, swUserPreferenceErrorDisplay_e.swUserPreferenceError_e_DisplayErrors)
swModel.ForceRebuild3(False)
MessageBox.Show($”An error occurred: {ex.Message}”, “Error”, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
5. Windows API の呼び出しとメモリ最適化
5.1. Windows API の呼び出し
‘ SolidWorksAddin.vb (クラスの先頭に追加)
‘ 例: MessageBox を表示する API
Public Shared Function MessageBox(ByVal hWnd As IntPtr, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Integer) As Integer
End Function
Public Shared Function ShellExecute(ByVal hwnd As IntPtr, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Integer) As IntPtr
End Function
Public Const MB_OK As Integer = 0
Public Const MB_ICONINFORMATION As Integer = 64
‘ SolidWorksAddin.vb (RunMyMacro メソッド内などに追加)
Dim result As Integer = MessageBox(IntPtr.Zero, “This is a message from Windows API.”, “API Example”, MB_OK Or MB_ICONINFORMATION)
‘ ShellExecute(IntPtr.Zero, “open”, “notepad.exe”, Nothing, Nothing, 1) ‘ SW_SHOWNORMAL
5.2. メモリ最適化とオブジェクトのライフサイクル管理
5.3. レガシー環境の保守と互換性
6. システム間連携の極限
まとめ
