【上級プロ】複数ユーザーの同時アクセスを想定したファイルロック回避:SolidWorksアセンブリの読取専用(Read-Only)自動判定と安全な排他制御
開発現場で最も恐ろしい瞬間の一つ。それは、血を吐く思いで作り込んだマクロが、他者がサーバー上で編集中(排他ロック中)のアセンブリを強引に上書き保存し、チーム全体の設計データを吹き飛ばした瞬間だ。
「え、VBAで開く前にロック判定なんてできるのか?」
「`OpenDoc6` の戻り値だけ見て安心していませんか?」
甘い。実務のネットワーク環境、特にPDM未導入の共有サーバーや、複数人が入り乱れる設計現場において、ファイルアクセスの競合は日常茶飯事だ。初心者レベルのコードであれば、ファイルが開けない瞬間に容赦なくVBAの実行時エラーが走り、Excelならともかく、重厚長大なSolidWorksのプロセスそのものが不安定になる。
今回は、複数ユーザーの同時アクセスを完全想定し、ファイルロックを華麗に回避、さらに「読取専用(Read-Only)」モードでの安全なインメモリ退避・自動判定ロジックを組み込んだ、プロダクションクオリティの堅牢な排他制御アーキテクチャを伝授する。
—
1. なぜ「力技のファイルオープン」は現場を崩壊させるのか?
多くのエンジニアが犯す最大の過ちは、次のようなコードを書いてしまうことだ。
‘ 【アンチパターン】絶対にやってはいけない実装
Dim swModel As ModelDoc2
Set swModel = swApp.OpenDoc6(“C:\SharedFolder\Assembly.sldasm”, swDocASSEMBLY, swOpenDocOptions_Silent, “”, longstatus, longwarnings)
‘ 他の人が開いていたらここでエラー、あるいは予期せぬ読取専用で開かれて後続処理が全滅
このアプローチが実務で通用しない理由は3つある。
1. 例外ハンドリングの欠如: ネットワーク越しの場合、ファイルがロックされているとSolidWorksはダイアログを出すか、サイレントモードであっても異常終了のリスクを孕む。
2. 「読取専用」の意図しない看過: 運良く開けたとしても、それが読取専用(Read-Only)であることに気づかず、マクロが最後に `Save3` を叩いた瞬間、アクセス権限エラーか、あるいは知らぬ間に別名保存の罠にハマる。
3. プロセスのブラックボックス化: 誰が、どの端末でロックしているのかというトレース情報が一切残らない。
プロのエンジニアであれば、「開く前にファイルの占有状態をOSレベル・SolidWorks APIレベルで多重チェックし、ロックされている場合は安全に処理を分岐(スキップ、または読取専用で安全にインスペクション)」する仕組みを構築しなければならない。
—
2. 堅牢な排他制御を実現する3つの防衛ライン
今回構築するアーキテクチャの全体像はこうだ。
1. FileSystemObject (FSO) による先行チェック:
OSレベルでファイルが別プロセス(他のSolidWorksインスタンスやExcelなど)に排他ロックされていないかを、VBのランタイム機能(`Open … For Binary Access Read Lock Read Write`)を用いて事前にプロービングする。
2. SolidWorks API (`OpenDoc7` / `GetDocumentState`) による状態判定:
ファイルを開く際のオプションを制御し、強制書込みを完全にブロックする。
3. 安全なグレースフル・デグラデーション(機能縮退):
ロックされている場合は、マクロを強制終了させるのではなく、「今回は読み取り専用で開いてレポートのみ生成する」「処理をスキップしてログに記録する」といった安全な離脱(Graceful Exit)を行う。
—
3. 【実装コード】プロダクション対応・排他制御モジュール
以下のコードは、エラーハンドリング、APIの厳密な型定義、そしてファイルロックの安全な検出を網羅した実務仕様のVBAモジュールである。そのままコピー&ペーストしてプロジェクトに組み込んでほしい。
Option Explicit
‘ ==============================================================================
‘ 模块名: modAssemblySafetyOpen
‘ 用途: 複数ユーザー環境におけるSolidWorksアセンブリの安全な排他制御とオープン
‘ ==============================================================================
‘ SolidWorks 定数の明示的定義(型安全性確保のため)
Private Const swDocASSEMBLY As Long = 2
Private Const swOpenDocOptions_Silent As Long = 1
Private Const swOpenDocOptions_ReadOnly As Long = 2
Private Const swDocLoadingError_AlreadyOpen As Long = 2
Public Sub SafeOpenAssemblyWorkflow()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim targetPath As String
targetPath = “C:\EngineeringData\SharedAssembly\HeavyMachine.sldasm”
‘ 【防衛ライン 1】ファイルが存在するか、そもそもOSレベルでアクセス可能か
If Not CheckFileAccessibility(targetPath) Then
MsgBox “対象ファイルは現在、他のユーザーまたはプロセスによって完全にロックされています。” & vbCrLf & _
“時間を置いて再度実行してください。”, vbCritical, “排他制御アラート”
Exit Sub
End If
‘ 【防衛ライン 2】SolidWorks APIを通じた安全なオープン処理
Dim swModel As ModelDoc2
Dim longstatus As Long
Dim longwarnings As Long
Dim isReadOnly As Boolean
‘ すでにSolidWorks内で開かれているか、他者に占有されているかを判定して開く
Set swModel = OpenAssemblyWithLockHandling(swApp, targetPath, isReadOnly, longstatus, longwarnings)
If swModel Is Nothing Then
MsgBox “アセンブリのロードに失敗しました。ステータスコード: ” & longstatus, vbCritical, “ロードエラー”
Exit Sub
End If
‘ 【防衛ライン 3】オープン後のモードに応じた処理の分岐
If isReadOnly Then
MsgBox “【注意】このアセンブリは現在「読取専用」で開かれてしまいました。” & vbCrLf & _
“他者が編中のため、本マクロによる自動保存・上書き処理はスキップされます。”, vbExclamation, “読取専用モード”
‘ 読取専用時の安全な処理(例:計測のみ、ツリー構造の解析のみ等)
PerformReadonlyOperations(swModel)
‘ 変更を加えずに閉じる
swApp.CloseDoc swModel.GetTitle
Else
MsgBox “排他権を獲得しました。正常に書き込み可能モードで処理を実行します。”, vbInformation, “排他制御OK”
‘ 書き込みを伴う主処理
PerformWriteOperations(swModel)
‘ 変更を保存して閉じる(必要に応じて)
‘ swModel.Save3 swSaveAsOptions_Silent, longstatus, longwarnings
swApp.CloseDoc swModel.GetTitle
End If
End Sub
/
- 1. OSレベルでのファイル排他・ロック状態を判定するプローブ関数
- @param filePath 対象ファイルのフルパス
- @return Boolean (True: アクセス可能 / False: ロック中)
/
Private Function CheckFileAccessibility(ByVal filePath As String) As Boolean
On Error GoTo ErrorHandler
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ ファイルが存在しない場合はFalse
If Not fso.FileExists(filePath) Then
CheckFileAccessibility = False
Exit Function
End If
‘ 実際に排他モードでファイルを一時オープンできるか試行する
‘ 他者が書き込み権限で開いている場合、このステートメントでエラーが発生する
Dim fileNum As Integer
fileNum = FreeFile
Open filePath For Binary Access Read Lock Write As #fileNum
Close #fileNum
CheckFileAccessibility = True
Exit Function
ErrorHandler:
‘ エラー番号 70 は「書き込み権限なし(Permission Denied)」
‘ ここで捕捉できれば、誰かがファイルを開いていると断定できる
CheckFileAccessibility = False
If fileNum > 0 Then Close #fileNum
End Function
/
- 2. SolidWorks APIを活用した堅牢なオープン処理
/
Private Function OpenAssemblyWithLockHandling(ByVal swApp As SldWorks.SldWorks, _
ByVal filePath As String, _
ByRef outIsReadOnly As Boolean, _
ByRef longstatus As Long, _
ByRef longwarnings As Long) As ModelDoc2
On Error GoTo ErrorHandler
Dim swModel As ModelDoc2
outIsReadOnly = False
‘ まずは通常モード(書き込み可能)でのオープンを試みる
‘ swOpenDocOptions_Silent を指定することで、不要なダイアログによるマクロのフリーズを防ぐ
Set swModel = swApp.OpenDoc7(filePath, swDocASSEMBLY, swOpenDocOptions_Silent, “”, longstatus, longwarnings)
If swModel Is Nothing Then
‘ 失敗した場合、すでに誰かが開いていることによる排他競合の可能性があるため、
‘ 読取専用(Read-Only)でのフォールバックオープンを試行する
Set swModel = swApp.OpenDoc7(filePath, swDocASSEMBLY, swOpenDocOptions_Silent + swOpenDocOptions_ReadOnly, “”, longstatus, longwarnings)
If Not swModel Is Nothing Then
outIsReadOnly = True
End If
Else
‘ 開けた場合でも、SolidWorks自体の機能で読取専用になっていないか最終確認
‘ (ドキュメントの読み取り専用プロパティをチェック)
outIsReadOnly = swModel.IsReadOnly
End If
Set OpenAssemblyWithLockHandling = swModel
Exit Function
ErrorHandler:
Set OpenAssemblyWithLockHandling = Nothing
End Function
Private Sub PerformReadonlyOperations(ByVal swModel As ModelDoc2)
‘ 読取専用時に安全に行える処理をここに記述
Debug.Print “ReadOnly Mode: ” & swModel.GetPathName
End Sub
Private Sub PerformWriteOperations(ByVal swModel As ModelDoc2)
‘ 書き込み・修正を伴う処理をここに記述
Debug.Print “Write Mode: ” & swModel.GetPathName
End Sub
—
4. チーフアーキテクトが解説するコードの急所
このコードが「なぜ現場でバグを起こさないのか」、その設計思想を深掘りする。
① `FreeFile` と `Open … For Binary` によるダブルチェック
SolidWorks APIを叩く前に、VBA標準のファイル入出力コマンドを用いてOSレベルでファイルをプロービングしている点がミソだ。
ネットワークサーバー上(CIFS/SMB環境など)では、SolidWorksのドキュメント管理機構が反応するよりも早く、OSのファイルロック状態を検知した方が圧倒的に動作が軽く、無駄なSolidWorksプロセスのロード・アンロードが発生しない。
② `OpenDoc7` とフォールバック戦略
旧来の `OpenDoc6` ではなく、より詳細なエラーハンドリングが可能な `OpenDoc7` を採用している。
もし書き込みモードでのオープンに失敗した場合、即座に例外落ちさせるのではなく、フラグを `swOpenDocOptions_ReadOnly` に切り替えて「安全な読取専用モード」へ自動フォールバックさせる。これにより、ユーザーは「マクロが勝手に落ちた」ではなく「現在は他者が編集中なので読み取り専用でデータを参照できた」という健全なユーザー体験を得られる。
③ サイレントモードとハングアップ防止
`swOpenDocOptions_Silent` を必ず付与している。サーバー上のアセンブリを開く際、コンポーネントの行方不明や、古いバージョンからのコンバート確認などのモーダルダイアログが出現すると、バックグラウンド実行やタスクスケジューラ連携の際にマクロが永遠に固まる(ハングする)。プロのコードにおいて、無防備なモーダルダイアログの発生は「バグ」と同義である。
—
5. 実運用に向けたアーキテクチャ上の注意点
- PDM(SOLIDWORKS PDM)環境との住み分けについて
もし社内でSOLIDWORKS PDMを使用している場合、ファイルへの直接アクセス(ファイルパス指定のオープン)ではなく、PDM API(`EdmLib`)を利用して「チェックアウト状態の確認」「ローカルキャッシュへの取得」を先に行うべきである。今回のコードは、いわゆる「PDMを導入していない共有ファイルサーバー(NAS等)」でマルチアクセスを行う現場において最大の効果を発揮する。
- ネットワーク遅延への配慮
VPNや遠隔拠点から社内サーバーのファイルにアクセスする場合、OSのファイルプロービング(`CheckFileAccessibility`)がタイムアウトを起こすことがある。その場合は、エラー監視の試行回数(リトライロジック)を数回挟むような拡張を行うと、さらに堅牢性が増すだろう。
—
総括
「動けばいい」というマインドで書かれたVBAは、チームの信頼を簡単に踏みにじる。排他制御を制する者は、SolidWorks自動化を制する。
今回解説した多重防衛ラインと読取専用の自動判定ロジックを現場のツールに組み込むことで、ファイル破損の恐怖から解放され、真に生産的なエンジニアリングに集中できる環境が手に入るはずだ。
あなたの書くコードが、チームの資産を守る強固な盾となることを期待する。
