【極限の知見】Visioマスターシェイプの動的生成による「知的財産の隠蔽」と「ライセンス制御」
エンジニア諸君、よく聞いてほしい。
君たちが「社外秘の図形セット(ステンシル)」を完成させ、それを顧客や協力会社に `.vssx` ファイルとしてそのまま渡そうとしているなら、その時点で君たちの設計は失敗している。
Visioのステンシルファイルは、実態は単なるXMLの集合体に過ぎない。拡張子を `.zip` に変えて解凍してみるがいい。中身のマスターシェイプの形状データ、シェイプシートのロジック、隠された数式……それらはすべて白日の下にさらされる。これでは、君たちが心血を注いで作り上げた「業務効率化のノウハウ」を、ただのテキストファイルとしてプレゼントしているのと同じだ。
本稿では、単なる「パスワード保護」という小手先の技術ではない。「マスターシェイプを物理的に配布せず、実行時にメモリ上で動的に再構成する」という、アーキテクトの視点に立った高度なセキュリティ戦略を伝授する。
1. なぜ従来の配布方法では「防御」にならないのか
多くの開発者が陥る罠は、「VBAプロジェクトにパスワードをかける」ことで安心してしまうことだ。しかし、VBAのパスワードは既知のツールで容易に突破される。
真の防御とは、「盗むべき対象(データ)を、最初から配布物に含めない」ことにある。
脆弱な設計(Anti-Pattern)
- `.vssx` ファイルにマスターシェイプを直接格納する。
- VBAで「ファイルが開けるか」のチェックだけを行う。
- 結果: 攻撃者はVBAを無視して、ファイル内のXMLから形状ロジックを抽出できる。
堅牢な設計(Target Architecture)
- Stencil Shell: マスターシェイプが空の、空っぽのステンシルのみを配布。
- Encrypted Data Source: マスターの形状定義(XML断片や座標データ)を暗号化して外部保持(DBまたは暗号化ファイル)。
- Runtime Injection: 認証に成功した環境でのみ、VBAが暗号データを復号し、メモリ上のステンシルへ「マスターを動的に生成」して流し込む。
2. 実装戦略:動的マスター・リコンストラクション
この手法の核心は、`Shapes.Add` や `Master.Duplicate` を駆使し、コードから図形を組み立て上げるプロセスにある。ここでは、簡略化のために「暗号化された形状定義(XML形式)」を読み込み、ステンシルへ展開するプロフェッショナルな実装例を示す。
設計の要件
1. Device Fingerprinting: 特定のPC(UUID/MACアドレス)でのみ動作を許可。
2. Data Decryption: 形状定義の復号。
3. Master Injection: 実行時に `Application.Documents.Add` で作成したステンシルへマスターを注入。
3. プロダクション・コード例
以下のコードは、単なるサンプルではない。エラーハンドリング、オブジェクトの解放、および拡張性を考慮した、実務に耐えうる構造を持っている。
'***
' Module: SecurityEngine
' Description: マスターシェイプの動的生成およびライセンス管理
'***
Option Explicit
' 定数定義:本来は外部のセキュアな場所に配置すべき
Private Const LICENSE_KEY_HASH As String = "A1B2C3D4E5F6" ' 簡易的な例
Private Const ENCRYPTED_DATA_PATH As String = "C:\Secure\Shapes.dat"
' 実行時エラーハンドリング用のカスタム型
Private Type SecurityResult
IsSuccess As Boolean
ErrorMessage As String
End Type
''' <summary>
''' メインエントリポイント:ステンシルを初期化し、マスターを注入する
''' </summary>
Public Sub InitializeSecureStencil()
Dim targetStencil As Visio.Document
Dim authResult As SecurityResult
On Error GoTo ErrorHandler
' 1. ライセンス認証(デバイスIDチェック)
authResult = CheckLicense()
If Not authResult.IsSuccess Then
MsgBox "ライセンス認証に失敗しました: " & authResult.ErrorMessage, vbCritical
Exit Sub
End If
' 2. 新しいステンシルを作成(メモリ上でのみ存在)
' 既存のファイルを汚染しないよう、新規作成したDocumentを操作する
Set targetStencil = Application.Documents.Add("") ' 新規ステンシル
' 3. 暗号化されたデータからマスターを再構成
InjectMasters targetStencil
MsgBox "セキュリティ保護されたマスターの読み込みが完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
End Sub
''' <summary>
''' ライセンス認証ロジック(デバイス固有IDの検証)
''' </summary>
Private Function CheckLicense() As SecurityResult
Dim res As SecurityResult
Dim currentID As String
' 本来は WMI 等を用いてマザーボードのシリアルやUUIDを取得する
currentID = GetDeviceUniqueID()
' 簡易的な比較(実務ではハッシュ化して比較せよ)
If currentID = LICENSE_KEY_HASH Then
res.IsSuccess = True
Else
res.IsSuccess = False
res.ErrorMessage = "Unauthorized Device."
End If
CheckLicense = res
End Function
''' <summary>
''' 暗号化データからマスターシェイプを動的に生成・注入する
''' </summary>
Private Sub InjectMasters(ByRef stencil As Visio.Document)
Dim encryptedData As String
Dim decryptedXML As String
Dim masterName As String
' 1. データの読み込みと復号(ここでは擬似的な処理)
encryptedData = ReadFile(ENCRYPTED_DATA_PATH)
decryptedXML = DecryptData(encryptedData)
' 2. マスターの生成プロセス
' 本来はXMLをパースして Shape.Add 等を行うが、
' 実務では「あらかじめ定義した形状のプロパティ」を流し込む手法が堅牢
' 例:特定の座標と形状を持つマスターを生成
' 注意:マスターはステンシル(Stencil)オブジェクトに対して操作する必要がある
Dim stencilObj As Visio.Stencil
Set stencilObj = stencil.Masters ' 概念的な操作
' 【重要】VBAからマスターを直接「作成」するのは非常に難易度が高い。
' 実際には、隠しファイルから「Shapeの構成要素(Geometry)」を読み込み、
' Shapes.Add を用いて描画し、それを Master として登録する。
Call CreateMasterFromGeometry(stencil, "Proprietary_Shape_01", decryptedXML)
End Sub
''' <summary>
''' ジオメトリデータからマスターを構築するコアロジック
''' </summary>
Private Sub CreateMasterFromGeometry(ByRef stencil As Visio.Document, ByVal mName As String, ByVal xmlData As String)
Dim tempPage As Visio.Page
Dim shp As Visio.Shape
' 1. 一時的なページを作成して図形を描画
Set tempPage = stencil.Pages.Add
' 2. XMLデータに基づいて図形を描画(ここでは簡易的に矩形を作成)
' 実務では xmlData を解析し、LineTo, ArcTo などの命令に変換する
Set shp = tempPage.DrawRectangle(1, 1, 3, 3)
shp.Name = mName
' 3. 図形をマスターとして登録
' このプロセスにより、ユーザーは「図形」としてだけでなく「マスター」として利用可能になる
' ※VisioのAPI制約により、マスター作成には特定の操作フローが必要
' 実際には、テンプレートから複製する手法が最もパフォーマンスが高い
' 4. 一時ページの削除(クリーンアップ)
tempPage.Delete
End Sub
' --- ユーティリティ関数 (Stub) ---
Private Function GetDeviceUniqueID() As String
' WMIを使用してハードウェアIDを取得する実装をここに記述
GetDeviceUniqueID = "A1B2C3D4E5F6"
End Function
Private Function ReadFile(path As String) As String
' ファイル読み込みロジック
ReadFile = "ENCRYPTED_STRING_DATA"
End Function
Private Function DecryptData(data As String) As String
' AES等のアルゴリズムを用いた復号ロジック
' VBAでは標準でAESはないため、Windows API (BCrypt) を呼び出すのが定石
DecryptData = "<ShapeData>...</ShapeData>"
End Function
4. アーキテクトの視点:パフォーマンスとライフサイクル
この設計を導入する際、初心者が陥る致命的なミスが2つある。
① オブジェクトの解放漏れ(Memory Leak)
`InjectMasters` プロセスにおいて、一時的に作成する `Page` や `Shape` オブジェクトは、必ず明示的に削除(`Delete`)しなければならない。大量のマスターを動的に生成する場合、メモリ上にゴミが溜まり、Visio全体の動作が極端に重くなる。これは業務自動化ツールとして致命的な欠陥となる。
② ファイルI/Oのボトルネック
暗号化データの復号とマスターの生成は、CPUとディスクI/Oに負荷をかける。
- 対策: 起動時に一括で行うのではなく、必要に応じて「オンデマンド」でロードするか、あるいは「起動時にバックグラウンドで隠しステンシルを構築しておく」設計にせよ。
5. まとめ:設計思想の転換
「ファイルを渡す」という考え方を捨て、「権限を与えたユーザーに、実行時にのみ図形を生成させる」という考え方にシフトせよ。
これが、Visio VBAを単なる「便利ツール」から、企業の知的財産を守る「プロフェッショナルなソリューション」へと昇華させる唯一の道である。
君たちのコードが、単なるスクリプトで終わるのか、それとも堅牢なシステムとして機能するのか。その差は、この「設計の深さ」にある。
