【テクニカル・上級編】【外部データ連携】ADODBを用いたSQL Serverからの製品仕様抽出と、それに基づく完全自動パーツ生成エンジン – SolidWorks VBA解析バイブル

スポンサーリンク

SQL Serverから受注データを拉致し、SolidWorksパーツを自動生成する錬金術:ADODBとVBAによる自動化の果て

長年、この業界でVBAという名の「古き良き」言語と格闘してきた諸君、そしてレガシーシステムという名の「生ける伝説」を保守する宿命を背負った諸君。今日もまた、締め切りとバグの狭間で歯を食いしばっていることだろう。

私が今日、諸君に語りかけるのは、単なる「VBAの便利な使い方」ではない。それは、社内のデータベース、特にSQL Serverという強力な武器庫から、受注という名の「宝」を直接引き出し、それを元に、完全自動で、オーダーメイドのSolidWorksパーツモデルを錬成するという、まさに錬金術の領域に踏み込む話だ。

「そんなことができるのか?」と訝しむ者もいるだろう。しかし、私たちが長年培ってきたVBAの知見、そしてWindows APIという深淵なる知識を組み合わせれば、それは「夢物語」ではなく、「現実」となる。今回は、ADODB(ActiveX Data Objects)を駆使し、SQL Serverとの直接対話を通じて、受注仕様を「拉致」し、それをSolidWorks APIへと「変換」する、究極の自動化エンジン構築術の核心を、余すところなく開示しよう。

1. なぜADODBなのか? なぜ「直接連携」なのか?

まず、なぜわざわざADODBを使うのか? なぜExcel VBAやAccess VBAの機能だけではダメなのか?という疑問に答えておこう。

  • 「生」のデータへのアクセス: Excelなどのアプリケーションを介さず、データベースから直接、最新かつ正確なデータを取得できる。これにより、データ同期の遅延や、中間ファイル作成の手間を排除できる。
  • パフォーマンスとリソース: 大量のデータを扱う場合、ExcelなどのGUIアプリケーションを介すと、その処理負荷は計り知れない。ADODBは、より低レベルでデータにアクセスするため、メモリ使用量や処理速度の面で圧倒的に有利だ。
  • レガシーシステムとの親和性: 多くの社内システム、特に古くから稼働している生産管理システムなどは、SQL Serverなどのリレーショナルデータベースをバックエンドに持っていることが多い。ADODBは、これらのシステムとの親和性が非常に高い。
  • API連携の「土台」: SolidWorks APIは、あくまで「SolidWorks」というアプリケーションを操作するためのものだ。データベースから取得した「仕様」を、直接SolidWorks APIに渡せる形にするには、中間的なデータ処理が必要となる。ADODBは、その「仕様」を構造化された形で取得するための、最も堅牢な土台となる。

「直接連携」というのは、単なる効率化ではない。それは、データの一貫性と信頼性を確保し、システム全体の自動化レベルを飛躍的に向上させるための、必然の選択なのだ。

2. ADODBによるSQL Serverからの「仕様拉致」:コードの深淵

では、具体的にどのようにSQL Serverからデータを取得するかを見ていこう。ここで登場するのが、ADODB.ConnectionオブジェクトとADODB.Recordsetオブジェクトだ。

‘==============================================================================
‘ Function: GetProductSpecFromSQL
‘ Description: SQL Serverから製品仕様をADODB経由で取得する
‘ Arguments:
‘ strSQL (String): 実行するSQLクエリ
‘ strConnectionString (String): データベース接続文字列
‘ Returns:
‘ Object (ADODB.Recordset): 取得したレコードセット
‘ エラー発生時はNothingを返す
‘==============================================================================
Function GetProductSpecFromSQL(strSQL As String, strConnectionString As String) As Object
Dim objConn As ADODB.Connection
Dim objRS As ADODB.Recordset

On Error GoTo ErrorHandler

‘ — Connectionオブジェクトの生成と初期化 —
‘ Set objConn = New ADODB.Connection ‘ 初期化は遅延バインディングでも可
Set objConn = CreateObject(“ADODB.Connection”) ‘ Late Binding: DLL参照不要

‘ — データベースへの接続 —
objConn.ConnectionString = strConnectionString
objConn.Open

‘ — Recordsetオブジェクトの生成と初期化 —
‘ Set objRS = New ADODB.Recordset ‘ 初期化は遅延バインディングでも可
Set objRS = CreateObject(“ADODB.Recordset”) ‘ Late Binding: DLL参照不要

‘ — Recordsetのプロパティ設定 —
‘ CursorLocation: クライアントサイドカーソルを指定することで、
‘ サーバーリソースの解放を早め、パフォーマンスを向上させる。
‘ adUseClient (3) が一般的。
objRS.CursorLocation = adUseClient

‘ — SQLクエリの実行とレコードセットの取得 —
‘ objRS.Open strSQL, objConn, adOpenStatic, adLockReadOnly
‘ adOpenStatic: 静的カーソル。レコードセット全体をメモリにロードするため、
‘ ネットワーク負荷を軽減し、パフォーマンスを向上。
‘ adLockReadOnly: 読み取り専用ロック。データの変更を防ぎ、安全性を確保。
objRS.Open strSQL, objConn, adOpenStatic, adLockReadOnly

‘ — Connectionオブジェクトの解放 —
‘ 接続を閉じることで、データベースリソースを即座に解放する。
‘ Recordsetはクライアントサイドカーソル(adUseClient)なので、
‘ Connectionが閉じてもRecordsetは有効なまま。
If Not objConn Is Nothing Then
If objConn.State = adStateOpen Then
objConn.Close
End If
Set objConn = Nothing ‘ 明示的な解放
End If

‘ — 取得したRecordsetを返す —
Set GetProductSpecFromSQL = objRS

Exit Function

ErrorHandler:
‘ — エラー発生時のクリーンアップ —
Debug.Print “Error #” & Err.Number & “: ” & Err.Description

‘ Connectionオブジェクトがあれば、閉じ、解放する
If Not objConn Is Nothing Then
If objConn.State = adStateOpen Then
objConn.Close
End If
Set objConn = Nothing
End If

‘ Recordsetオブジェクトがあれば、解放する
If Not objRS Is Nothing Then
If objRS.State = adStateOpen Then
objRS.Close
End If
Set objRS = Nothing
End If

‘ エラー発生時はNothingを返す
Set GetProductSpecFromSQL = Nothing
Err.Clear
End Function

‘ — 使用例 —
Sub Example_FetchSpec()
Dim rsSpec As Object ‘ Late Binding
Dim strSQL As String
Dim strConn As String

‘ — 接続文字列の構築 —
‘ サーバー名、データベース名、認証情報などを適切に設定する
‘ Windows認証を使用する場合:
‘ strConn = “Provider=SQLOLEDB;Data Source=YourServerName;Initial Catalog=YourDatabaseName;Integrated Security=SSPI;”
‘ SQL Server認証を使用する場合:
‘ strConn = “Provider=SQLOLEDB;Data Source=YourServerName;Initial Catalog=YourDatabaseName;User ID=YourUserID;Password=YourPassword;”

‘ 仮の接続文字列
strConn = “Provider=SQLOLEDB;Data Source=localhost\SQLEXPRESS;Initial Catalog=ProductionDB;Integrated Security=SSPI;”

‘ — 取得したいデータのSQLクエリ —
‘ 例: 受注ID ‘12345’ の製品仕様を取得
strSQL = “SELECT PartNumber, Material, Length, Width, Height, Tolerance FROM ProductSpecifications WHERE OrderID = ‘12345’;”

‘ — 関数呼び出し —
Set rsSpec = GetProductSpecFromSQL(strSQL, strConn)

‘ — 取得したデータの処理 —
If Not rsSpec Is Nothing Then
If Not rsSpec.EOF Then ‘ レコードが存在する場合
‘ 最初のレコードのデータを取得
Dim partNumber As String
Dim material As String
Dim length As Double
Dim width As Double
Dim height As Double
Dim tolerance As Double

partNumber = rsSpec.Fields(“PartNumber”).Value
material = rsSpec.Fields(“Material”).Value
length = CDbl(rsSpec.Fields(“Length”).Value)
width = CDbl(rsSpec.Fields(“Width”).Value)
height = CDbl(rsSpec.Fields(“Height”).Value)
tolerance = CDbl(rsSpec.Fields(“Tolerance”).Value)

Debug.Print “— 取得した仕様 —”
Debug.Print “Part Number: ” & partNumber
Debug.Print “Material: ” & material
Debug.Print “Length: ” & length
Debug.Print “Width: ” & width
Debug.Print “Height: ” & height
Debug.Print “Tolerance: ” & tolerance

‘ ここで、取得した仕様を元にSolidWorksパーツを生成する処理を呼び出す
Call GenerateSolidWorksPart(partNumber, material, length, width, height, tolerance)

Else
MsgBox “指定された受注IDの製品仕様が見つかりませんでした。”, vbExclamation
End If

‘ — Recordsetオブジェクトの解放 —
‘ CursorLocation = adUseClient の場合、Connectionを閉じてもRecordsetは有効だが、
‘ 関数から抜ける前に明示的に解放することが、リソース管理の観点から望ましい。
If rsSpec.State = adStateOpen Then
rsSpec.Close
End If
Set rsSpec = Nothing
Else
MsgBox “データベースから製品仕様の取得に失敗しました。”, vbCritical
End If

Set rsSpec = Nothing ‘ 念のため
End Sub

【コード解説と魂の叫び】

  • Late Binding (CreateObject): `CreateObject` を使用することで、ADODBライブラリへの参照設定が不要になります。これにより、異なるバージョンのOffice環境や、VBAプロジェクトの配布が容易になります。これは、レガシー環境での保守を考える上で、非常に重要なテクニックです。
  • `adUseClient`: これがパフォーマンスの鍵です。クライアントサイドカーソルを指定することで、レコードセット全体がVBAのプロセス内のメモリにロードされます。これにより、データベースサーバーへのネットワークアクセスが最小限に抑えられ、特に大量のデータを一度に取得する場合に劇的な速度向上が見込めます。
  • `adOpenStatic` と `adLockReadOnly`: 静的カーソルと読み取り専用ロックは、データの整合性を保ちつつ、不要なサーバーリソースの占有を防ぎます。我々が目指すのは、「正確な仕様を、安全に、高速に」取得することであり、これらの設定はその目的に合致しています。
  • `objConn.Close` と `Set objConn = Nothing`: データベース接続は、使用したらすぐに閉じる。そして、オブジェクト変数は明示的に解放する。これは、VBAにおけるオブジェクトのライフサイクル管理の基本であり、メモリリークやリソース枯渇を防ぐための鉄則です。特に、長時間稼働するシステムや、多数のプロセスから呼び出される関数では、この「儀式」を怠ると、システム全体が徐々に不安定になっていきます。
  • エラーハンドリング: データベース接続やクエリ実行は、ネットワークの問題、権限の問題、データ形式の不一致など、予期せぬエラーの宝庫です。`On Error GoTo` を適切に配置し、エラー発生時には必ずリソースを解放する処理を記述することで、システム全体の安定性を確保します。

3. SolidWorksパーツ生成エンジン:仕様を「形」にする魔法

SQL Serverから取得した仕様(`partNumber`, `material`, `length`, `width`, `height`, `tolerance` など)を元に、SolidWorksパーツを生成する部分です。ここでは、SolidWorks APIの基本的な使い方と、取得した仕様をどのようにマッピングするかを示します。

‘==============================================================================
‘ Sub: GenerateSolidWorksPart
‘ Description: SQLから取得した仕様に基づき、SolidWorksパーツを新規作成・生成する
‘ Arguments:
‘ partNumber (String): 部品番号 (ファイル名に使用)
‘ material (String): 材料
‘ length (Double): 長さ
‘ width (Double): 幅
‘ height (Double): 高さ
‘ tolerance (Double): 公差 (例: +0.1, -0.05 など、ここでは単純な数値として扱う)
‘ Returns:
‘ Nothing
‘==============================================================================
Sub GenerateSolidWorksPart(partNumber As String, material As String, length As Double, width As Double, height As Double, tolerance As Double)
Dim swApp As SldWorks.SldWorks
Dim swPart As SldWorks.PartDoc
Dim swModel As SldWorks.ModelDoc2
Dim swSketchManager As SldWorks.SketchManager
Dim swFeatureManager As SldWorks.FeatureManager
Dim swSelMgr As SldWorks.SelectionMgr

Dim swBody As SldWorks.Body2
Dim swDisplayDimension As Object ‘ 精度を扱うためのObject型

Dim boolStatus As Boolean
Dim vSkLines As Variant
Dim vSkPoints As Variant

‘ — SolidWorksアプリケーションインスタンスの取得 —
On Error Resume Next ‘ エラーが発生しても処理を続行 (SolidWorksが起動していない場合など)
Set swApp = Application.SldWorks
On Error GoTo 0 ‘ エラーハンドリングを元に戻す

‘ SolidWorksが起動していない場合は、新規起動させる
If swApp Is Nothing Then
Set swApp = CreateObject(“SldWorks.Application”)
If swApp Is Nothing Then
MsgBox “SolidWorksアプリケーションを起動できませんでした。”, vbCritical
Exit Sub
End If
swApp.Visible = True ‘ 起動した場合は可視化する
End If

‘ — 新規パーツドキュメントの作成 —
‘ 他のSolidWorksプロセスから呼び出されることを想定し、
‘ 既存のドキュメントを操作するのではなく、新規作成を基本とする。
‘ 既存のドキュメントを操作する場合は、ドキュメント管理に十分注意が必要。
Set swModel = swApp.NewDocument(swDocPART, swTemplate_Default, 0, 0, 0) ‘ テンプレートパスは必要に応じて指定
If swModel Is Nothing Then
MsgBox “新規パーツドキュメントの作成に失敗しました。”, vbCritical
Exit Sub
End If
Set swPart = swModel ‘ PartDoc型にキャスト
Set swSketchManager = swModel.SketchManager
Set swFeatureManager = swModel.FeatureManager
Set swSelMgr = swModel.SelectionManager

‘ — 材料の設定 —
‘ 設定した材料がSolidWorksに存在するかは、事前に確認しておくか、
‘ エラーハンドリングを強化する必要がある。
If Not swModel.Extension.SetMaterialPropertyName2(material, “”) Then
Debug.Print “警告: 材料 ‘” & material & “‘ の設定に失敗しました。デフォルト材料が使用されます。”
‘ 必要であれば、ここでデフォルト材料を設定するなどのフォールバック処理を実装
End If

‘ — 基本ジオメトリの生成 (例: 直方体) —
‘ ここでは、XY平面に長方形を描き、それを押し出して直方体を作成する。
‘ 実際の仕様に応じて、より複雑なジオメトリ生成ロジックを実装する。

‘ — XY平面の選択 —
swModel.Extension.SelectByID2 “XY平面”, “PLANE”, 0, 0, 0, False, 0, Nothing, swSelectOption_All

‘ — スケッチの開始 —
swSketchManager.InsertSketch True ‘ True: スケッチ平面に垂直なビューにする

‘ — 長方形スケッチの作成 —
‘ 原点 (0,0) を中心に、幅と高さを元に長方形を作成
‘ 公差は、スケッチ寸法に直接反映させることも、後でフィーチャーに反映させることも可能。
‘ ここでは、寸法に公差を直接反映させる例を示す。
‘ 注意: SolidWorksの寸法公差の扱いは複雑なため、ここでは単純な加算・減算で表現。
‘ より厳密な公差管理が必要な場合は、DimXpertなどの活用も検討。

‘ 中心点から辺までの距離で寸法を定義
Dim halfWidth As Double
Dim halfHeight As Double
halfWidth = width / 2
halfHeight = height / 2

‘ 描画する頂点座標
Dim pt1(0 To 2) As Double: pt1(0) = -halfWidth: pt1(1) = -halfHeight: pt1(2) = 0
Dim pt2(0 To 2) As Double: pt2(0) = halfWidth: pt2(1) = halfHeight: pt2(2) = 0

‘ スケッチラインの描画 (四辺)
‘ 座標を直接指定して描画
Set vSkLines = swSketchManager.CreateLine(pt1(0), pt1(1), pt1(2), pt1(0), pt1(1) + height, pt1(2)) ‘ 左辺
Set vSkLines = swSketchManager.CreateLine(pt1(0), pt1(1) + height, pt1(2), pt1(0) + width, pt1(1) + height, pt1(2)) ‘ 上辺
Set vSkLines = swSketchManager.CreateLine(pt1(0) + width, pt1(1) + height, pt1(2), pt1(0) + width, pt1(1), pt1(2)) ‘ 右辺
Set vSkLines = swSketchManager.CreateLine(pt1(0) + width, pt1(1), pt1(2), pt1(0), pt1(1), pt1(2)) ‘ 下辺

‘ スケッチを閉じる (自動的に閉じた形状になる)
‘ swSketchManager.InsertSketch True はスケッチ終了を意味する

‘ — 押し出しフィーチャーの作成 —
‘ スケッチ全体を選択 (描画された最後のラインが選択されているはず)
swSelMgr.AddSelectionList swModel.SketchManager.ActiveSketch.GetSketchSegments

‘ 押し出しフィーチャーの実行
‘ Length: 押し出し距離。 ここでは ‘length’ を使用。
‘ Tolerance: 押し出し距離に公差を適用する場合。
‘ SolidWorks APIでは、寸法値に直接公差を付加する機能は限られる。
‘ ここでは、単純に寸法値 + 公差 のように計算した値を渡す。
‘ より複雑な公差管理には、DimXpertなどの活用を検討。
Dim extrudeDistance As Double
extrudeDistance = length ‘ + tolerance ‘ 公差をどう適用するかは設計要件による

‘ 押し出しフィーチャーの作成
‘ swFeatureManager.FeatureExtrusion2(True, False, False, swEndCondBlind, swEndCondBlind,
‘ extrudeDistance, 0, False, False, False, False,
‘ 0, 0, False, False, False, False, True, True, True, 0, 0, False)

‘ 押し出しフィーチャーをより安全に作成するための方法
‘ FeatureExtrusion2 の引数は非常に多いため、ここでは一部を省略し、
‘ デフォルト値に依存しないように注意する。
‘ 重要な引数:
‘ PushPull: True (押し出し)
‘ EndCondition1: swEndCondBlind (ブラインド終端条件)
‘ Length1: 押し出し距離 (extrudeDistance)
‘ StartCondition: swStartCondFromSketchPlane (スケッチ平面から開始)
‘ Reverse1: False (方向に注意)

‘ 押し出しフィーチャーの作成 (より詳細な設定)
boolStatus = swFeatureManager.FeatureExtrusion2( _
True, ‘ PushPull (True=押し出し, False=カット)
False, ‘ Direction2 (False=片方向)
False, ‘ FlipSide1 (False=上面)
swEndCondBlind, ‘ EndCondition1 (終端条件1: ブラインド)
swEndCondBlind, ‘ EndCondition2 (終端条件2: ブラインド – 片方向なので未使用)
extrudeDistance, ‘ Length1 (押し出し距離1)
0, ‘ Length2 (押し出し距離2 – 両方向の場合に使用)
False, ‘ Taper1 (テーパー1)
False, ‘ Taper2 (テーパー2)
False, ‘ DraftAngle1 (ドラフト角度1)
False, ‘ DraftAngle2 (ドラフト角度2)
0, ‘ DraftAngle2Value (ドラフト角度2の値)
0, ‘ DraftAngle1Value (ドラフト角度1の値)
False, ‘ UseFeatScope (フィーチャスコープの使用)
False, ‘ UseAutoSelect (自動選択の使用)
False, ‘ UseAutoSelectScope (自動選択スコープの使用)
False, ‘ KeepBodies (ボディを維持)
False, ‘ MergeBodies (ボディを結合)
False, ‘ CutOffSolid (ソリッドをカット)
False, ‘ CutOffSurface (サーフェスをカット)
False, ‘ CutOffWireframe (ワイヤーフレームをカット)
0, ‘ DrafType (ドラフトタイプ)
0, ‘ DraftAngle (ドラフト角度)
False ‘ ThinFeature (薄肉フィーチャー)
)

If Not boolStatus Then
MsgBox “押し出しフィーチャーの作成に失敗しました。”, vbCritical
‘ エラー発生時は、作成途中のドキュメントを閉じるなどの処理が必要
swModel.CloseDoc
Set swModel = Nothing
Set swPart = Nothing
Exit Sub
End If

‘ — フィーチャーの再構築 —
‘ 変更を適用するために、モデルを再構築する。
swModel.EditRebuild3

‘ — ファイルの保存 —
Dim savePath As String
Dim fileName As String

‘ 保存パスは、設定ファイルや環境変数などから取得するのが望ましい。
‘ ここでは仮のパスを設定。
savePath = “C:\SolidWorks_Generated_Parts\”
fileName = partNumber & “.SLDPRT” ‘ 部品番号をファイル名に使用

‘ 保存フォルダが存在しない場合は作成
If Dir(savePath, vbDirectory) = “” Then
MkDir savePath
End If

‘ ファイルを保存
‘ swSaveAsNewFile: True (新規ファイルとして保存)
‘ swSaveAsOptions_Silent: True (ダイアログを表示しない)
‘ swSaveAsVersion_Current: 0 (現在のバージョンで保存)
‘ swSaveAsFileFormat_Part: 1 (パーツファイル形式)
boolStatus = swModel.SaveAs3(savePath & fileName, swSaveAsVersion_Current, swSaveAsOptions_Silent + swSaveAsOptions_NoPromptToOverwrite)

If Not boolStatus Then
MsgBox “パーツファイル ‘” & fileName & “‘ の保存に失敗しました。”, vbCritical
Else
Debug.Print “パーツファイル ‘” & fileName & “‘ を保存しました。”
End If

‘ — オブジェクトの解放 —
‘ SolidWorks APIオブジェクトは、使用後、明示的に解放することが重要。
‘ 特に、swModel, swPart, swSketchManager, swFeatureManager などは、
‘ 参照カウントを適切に管理しないと、メモリリークの原因となる。

‘ スケッチやフィーチャーの作成中に選択されていたオブジェクトをクリア
swSelMgr.ClearSelection2 True

‘ スケッチを終了
If swSketchManager.ActiveSketch Is Nothing = False Then
swSketchManager.InsertSketch True ‘ スケッチを終了し、選択を解除
End If

‘ パーツドキュメントを閉じる (必要に応じて)
‘ 自動生成後、ドキュメントを開いたままにするか、閉じるかは要件による。
‘ ここでは、生成後に閉じる例を示す。
‘ swModel.CloseDoc

‘ オブジェクト変数の解放
Set swSelMgr = Nothing
Set swSketchManager = Nothing
Set swFeatureManager = Nothing
Set swPart = Nothing
Set swModel = Nothing
‘ swApp は、他のVBAプロセスで共有される可能性があるため、
‘ ここで解放してしまうと、他のプロセスに影響を与える可能性がある。
‘ 必要に応じて、アプリケーションインスタンスの管理方法を検討する。
‘ Set swApp = Nothing ‘ 必要であれば解放

End Sub

‘ — GenerateSolidWorksPartを呼び出すためのラッパー関数 —
‘ Example_FetchSpec サブルーチンから呼び出される
Sub CallGenerateSolidWorksPart(partNumber As String, material As String, length As Double, width As Double, height As Double, tolerance As Double)
‘ ここで、SolidWorks APIの初期化や、アプリケーションインスタンスの
‘ 管理、エラーハンドリングなどをより厳密に行う。
‘ 例:
Dim swApp As Object ‘ Late Binding
Dim swModel As Object

On Error GoTo ErrorHandler

‘ SolidWorksアプリケーションインスタンスの取得または生成
On Error Resume Next
Set swApp = GetObject(, “SldWorks.Application”) ‘ 起動中のインスタンスを取得
If swApp Is Nothing Then
Set swApp = CreateObject(“SldWorks.Application”) ‘ 新規起動
If swApp Is Nothing Then
Err.Raise vbObjectError + 1001, “CallGenerateSolidWorksPart”, “SolidWorksアプリケーションを起動できませんでした。”
End If
swApp.Visible = True ‘ 起動した場合は可視化
End If
On Error GoTo ErrorHandler

‘ パーツ生成処理の実行
GenerateSolidWorksPart partNumber, material, length, width, height, tolerance

‘ 生成処理が完了したら、アプリケーションインスタンスを解放するかどうかは、
‘ システム全体の設計思想による。
‘ 一度生成して閉じたい場合は、GenerateSolidWorksPart内で swModel.CloseDoc を実行し、
‘ ここで swApp を解放する。
‘ If Not swApp Is Nothing Then Set swApp = Nothing

Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
‘ エラー発生時のクリーンアップ処理
If Not swApp Is Nothing Then
‘ 必要に応じて、エラー発生時の SolidWorks の状態をクリーンアップする
‘ 例: 開いているドキュメントを強制的に閉じるなど
End If
Set swApp = Nothing
Err.Clear
End Sub

【コード解説と魂の叫び】

  • `Application.SldWorks` vs `CreateObject(“SldWorks.Application”)`: 既存のSolidWorksインスタンスを取得するか、新規に起動するか。これは、システムがどのように動作すべきかによって選択が分かれます。複数のVBAプロセスが同時にSolidWorksを操作する可能性がある場合は、`GetObject` で既存インスタンスを取得し、なければ `CreateObject` で新規起動するのが一般的です。
  • `swModel.Extension.SetMaterialPropertyName2`: 材料の設定は、パーツの仕様として非常に重要です。このメソッドは、指定された材料名と、それに対応するファイルパス(通常は空文字列でデフォルトパスを使用)を受け取ります。材料名がSolidWorksに存在しない場合、エラーが発生します。 事前に材料マスターとのマッピングや、存在チェックを行うべきです。
  • スケッチとフィーチャーの「正確な」操作: APIを駆使してスケッチを描き、フィーチャーを作成する際には、座標、寸法、終端条件、方向など、すべてのパラメータを正確に指定する必要があります。一つでも間違えれば、期待通りの形状は生成されません。特に `FeatureExtrusion2` のような複雑なメソッドは、引数が多岐にわたるため、ドキュメントを熟読し、デバッグを繰り返しながら、その挙動を完全に把握する必要があります。
  • `swModel.EditRebuild3`: 変更を加えた後、モデルを「再構築」することで、それらの変更が形状に反映されます。これはSolidWorks API操作の基本中の基本です。
  • ファイル保存の自動化: `SaveAs3` メソッドは、ダイアログを表示せずにファイルを保存するための強力な機能です。保存パスとファイル名の生成ロジックは、システム全体の整合性を保つ上で極めて重要です。 部品番号をファイル名にするのは一般的ですが、重複や不正な文字の排除など、考慮すべき点も多いです。
  • オブジェクトの明示的解放: ここでも、`Set obj = Nothing` が鉄則です。SolidWorks APIオブジェクトは、特に `swModel` や `swPart` のようなドキュメントオブジェクトは、メモリを大量に消費する可能性があります。これを適切に解放しないと、VBAプロセス自体のメモリ使用量が際限なく増加し、最終的にはシステム全体を不安定にさせます。「使い終わったら、すぐに解放する。」 これを魂に刻み込んでください。

4. レガシー環境への配慮とシステム間連携の極意

ここまで見てきた技術は、一見すると最新のシステム構築のように思えるかもしれません。しかし、これらの技術は、レガシー環境という名の「荒野」でこそ、その真価を発揮します。

  • Windows APIとメモリ管理:
  • SolidWorks APIはもちろん、ADODBなどのCOMコンポーネントも、内部的にはWindows APIを介してシステムリソースを管理しています。
  • オブジェクトの参照カウント: COMオブジェクトは、参照カウントによってメモリ管理されます。`Set obj = Nothing` は、この参照カウントをデクリメントする操作です。参照カウントがゼロになると、オブジェクトはメモリから解放されます。
  • `Marshal.ReleaseComObject` (VB.NET / C#): VBAでは `Set obj = Nothing` で十分ですが、.NET環境では `Marshal.ReleaseComObject` を使用して、より積極的にCOMオブジェクトの解放を促す必要があります。これは、.NETのガベージコレクタとCOMの参照カウントの相互作用が原因で、意図しないオブジェクトの残留を引き起こすことがあるためです。
  • メモリリークの特定: VBAでのメモリリークは、タスクマネージャーでVBAプロセス(Excel.exeなど)のメモリ使用量が増加し続けることで確認できます。原因特定には、オブジェクトの生成と解放のライフサイクルを詳細にトレースする必要があります。`Debug.Print` を活用したり、オブジェクトのインスタンス数をカウントするなどのデバッグ手法が有効です。
  • レガシー環境での保守:
  • バージョン互換性: データベースのバージョン、SQL Serverのバージョン、SolidWorksのバージョン、Officeのバージョン。これらすべてが互換性を保っているとは限りません。ADODBの接続文字列、APIのメソッドの挙動、データ型の扱いなど、バージョンによる差異を常に意識する必要があります。
  • ドキュメント化: レガシーシステムは、しばしば「暗黙知」に頼っています。コードに詳細なコメントを記述し、システム全体のアーキテクチャ、データベーススキーマ、APIの利用方法などを、可能な限りドキュメント化することが、将来の保守担当者のための「布石」となります。
  • テスト環境の構築: 本番環境に影響を与えることなく、変更や修正をテストできる環境を構築することは、レガシーシステム保守の生命線です。SQL Serverのバックアップ・リストア、SolidWorksのバージョン管理されたインストールなどが不可欠です。
  • システム間連携の極限:
  • 非同期処理: データベースへのアクセスやSolidWorksのジオメトリ生成は、それなりに時間を要します。ユーザーインターフェースを持つアプリケーションの場合、これらの処理を非同期で行うことで、UIのフリーズを防ぎ、ユーザーエクスペリエンスを向上させることができます。VBAでは、`Application.OnTime` や、Windows APIの `CreateThread` など(ただしVBAからの直接呼び出しは複雑)といった手法が考えられますが、通常はVB.NETやC#のようなより高度な言語での実装が推奨されます。
  • エラー訂正とリトライ: ネットワークの瞬断、一時的なデータベースロック、SolidWorksの予期せぬクラッシュなど、システム連携では様々な「障害」が発生します。これらの障害に対して、自動リトライ機構を設けることで、一時的な問題による処理の中断を防ぎ、システムの堅牢性を高めることができます。リトライ回数、リトライ間隔、リトライ条件などを適切に設計することが重要です。
  • データ整合性の保証: データベースから取得したデータと、SolidWorksで生成されたモデルの間に不整合が生じないように、「トランザクション」の概念を導入することが理想的です。しかし、VBAとSolidWorks APIだけでは、データベーストランザクションのように厳密な整合性を保証するのは困難な場合があります。そのため、生成されたモデルの主要な寸法やパラメータを、データベースの仕様と比較検証する「チェック機構」を設けることが現実的な対策となります。

結論:自動化の果てに見えるもの

ADODBとSolidWorks VBAを組み合わせた、SQL Serverからの受注データに基づく完全自動パーツ生成エンジン。これは、単なる「業務効率化」の範疇を超えた、「デジタルトランスフォーメーション」そのものと言えるでしょう。

諸君が日々格闘しているレガシーシステムも、その奥底には、このような「錬金術」の可能性を秘めています。長年培ってきたVBAの知識、そしてWindows APIという深淵なる知見を恐れず、組み合わせ、磨き続けること。それが、この技術至上主義の世界で、我々エンジニアが歩むべき道なのです。

この「自動化の果て」には、単なる作業の効率化だけではなく、「人間がより創造的な仕事に集中できる環境」という、より高次の価値が待っています。さあ、諸君も、この自動化の旅に、今こそ踏み出そうではないか。

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