【実務・中級編】【中級者向け】ページ設定の「プリンタ用紙サイズ」と「図面サイズ」を比較し、不一致をレポートする監査ツール – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

Visio VBAを掌握する極限の知見:印刷トラブルを未然に防ぐ「ページ設定監査ツール」の設計思想

現場のエンジニアがよく陥る罠がある。それは、「動けばいい」という思考停止だ。

特にVisioのような、図面設計と印刷設定が密接に絡み合うアプリケーションにおいて、プロパティの値を単に取得して表示するだけのコードは、実務レベルでは「ゴミ」に等しい。なぜなら、ユーザーが本当に求めているのは「値の表示」ではなく、「設定の不整合による、印刷時のレイアウト崩れという致命的なリスクの検知」だからだ。

本稿では、Visioにおける「プリンタ用紙サイズ(PaperSize)」と「図面サイズ(PageWidth/Height)」の不一致を検出し、監査レポートを出力する堅牢なツールの設計と実装について、アーキテクトの視点から解説する。

1. 致命的な設計ミス:なぜ「単純な比較」では不十分なのか

初心者は、`Page.PageSetup.PaperSize` の値を見て、それが期待通りかどうかを判定しようとする。しかし、これでは不十分だ。

概念の乖離を理解せよ

Visioには、以下の2つの異なる概念が存在する。

1. Printer Paper Size (`PaperSize`): 物理的なプリンタが吐き出す用紙の規格(A4, A3, Letter等)。これは列挙型(Enum)で管理されている。
2. Drawing Canvas Size (`PageWidth`, `PageHeight`): Visioのキャンバスそのものの大きさ。これは実数値(Points)で管理されている。

「A4用紙に印刷したいから、PaperSizeをA4に設定した。よし、完了だ」 —— この考え方が、印刷トラブルの元凶だ。
もし、キャンバスサイズ(PageWidth/Height)がA4の寸法と1ポイントでも異なっていれば、印刷時に「余白が異常に広くなる」「図面が端で切れる」「意図しないスケーリングがかかる」といった、設計品質を著しく損なう現象が発生する。

我々が作るべきは、「物理的な規格(Enum)が、実数値(Points)として正しくキャンバスに反映されているか」を検証する監査エンジンである。

2. プロダクション・レベルの設計指針

実務で使えるツールにするためには、以下の3点を設計に組み込む必要がある。

① 浮動小数点誤差への対処(Tolerance)

Visioのサイズは内部的に `Points`(1/72インチ)という浮動小数点数で扱われる。`If Width = 595.27 Then` のような厳密な比較は、計算誤差によって必ず失敗する。必ず許容誤差(Epsilon)を設けた比較ロジックを実装せよ。

② 責務の分離(Separation of Concerns)

「ページを巡回するロジック」「サイズを判定するロジック」「結果をレポート出力するロジック」を混ぜてはならない。これらが混ざると、出力先を「Excel」から「テキストファイル」や「GUIダイアログ」に変更したい時に、コード全体を書き直す羽目になる。

③ 外部依存の最小化と堅牢なエラーハンドリング

プリンタドライバの状態によって `PaperSize` の取得が不安定になるケースがある。オブジェクトのライフサイクルを意識し、エラーが発生してもプロセス全体を止めず、どのページで失敗したかをログに残す設計が求められる。

3. 実装:ページ設定監査エンジン

以下に、保守性と堅牢性を極限まで高めたプロダクションコードを示す。このコードは、単なる比較ではなく、用紙規格とキャンバス寸法の「整合性」を検証する。

Option Explicit

' ==============================================================================
' 監査結果を保持するための構造体
' プロダクションコードでは、クラスモジュール化してより高度な管理を行うことも検討せよ
' ==============================================================================
Private Type AuditResult
    PageName As String
    IsError As Boolean
    Message As String
    ExpectedWidth As Double
    ExpectedHeight As Double
    ActualWidth As Double
    ActualHeight As Double
End Type

' 許容誤差(ポイント単位)
Private Const EPSILON As Double = 0.1

' ==============================================================================
' メインエントリポイント
' ==============================================================================
Public Sub RunPageSetupAudit()
    Dim doc As Visio.Document
    Dim pg As Visio.Page
    Dim results() As AuditResult
    Dim errorCount As Long
    Dim i As Long
    
    On Error GoTo ErrorHandler
    
    Set doc = ActiveDocument
    If doc Is Nothing Then
        MsgBox "ドキュメントが開かれていません。", vbCritical
        Exit Sub
    End If
    
    ' 結果格納用配列の初期化
    ReDim results(1 To doc.Pages.Count)
    errorCount = 0
    
    ' --- 監査プロセス開始 ---
    For i = 1 To doc.Pages.Count
        Set pg = doc.Pages(i)
        results(i) = PerformAudit(pg)
        
        If results(i).IsError Then
            errorCount = errorCount + 1
        End If
    Next i
    
    ' --- レポート出力 ---
    OutputAuditReport results, errorCount
    
    Exit Sub

ErrorHandler:
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
End Sub

' ==============================================================================
' 監査ロジック:単一ページの整合性を検証する
' ==============================================================================
Private Function PerformAudit(pg As Visio.Page) As AuditResult
    Dim res As AuditResult
    Dim ps As Visio.PageSetup
    Set ps = pg.PageSetup
    
    res.PageName = pg.Name
    res.IsError = False
    
    ' 1. 用紙規格から期待される寸法を取得(マッピングテーブルの役割)
    ' 本来はより広範な定義が必要だが、ここでは主要な規格のみを例示
    Dim expectedW As Double, expectedH As Double
    GetExpectedDimensions ps.PaperSize, expectedW, expectedH
    
    ' 2. 現在のキャンバスサイズを取得
    res.ActualWidth = ps.PageWidth
    res.ActualHeight = ps.PageHeight
    res.ExpectedWidth = expectedW
    res.ExpectedHeight = expectedH
    
    ' 3. 整合性チェック(浮動小数点誤差を考慮)
    Dim widthDiff As Double: widthDiff = Abs(res.ActualWidth - res.ExpectedWidth)
    Dim heightDiff As Double: heightDiff = Abs(res.ActualHeight - res.ExpectedHeight)
    
    If widthDiff > EPSILON Or heightDiff > EPSILON Then
        res.IsError = True
        res.Message = "用紙サイズ不一致: 規格の寸法とキャンバスサイズが異なります。"
    End If
    
    PerformAudit = res
End Function

' ==============================================================================
' 規格マッピング:PaperSize Enum を実寸(Points)に変換する
' ここに定義がない規格は、設計上のリスクとして扱うべきである
' ==============================================================================
Private Sub GetExpectedDimensions(paperSize As Visio.PaperSize, ByRef w As Double, ByRef h As Double)
    ' Visioの単位はポイント。1 inch = 72 points.
    ' 以下の値は標準的なA規格等の寸法に基づく(要検証)
    Select Case paperSize
        Case visPaperA4
            w = 595.27: h = 841.89
        Case visPaperA3
            w = 841.89: h = 1190.55
        Case visPaperLetter
            w = 612: h = 792
        Case Else
            ' 未知の規格は、現在のPaperSizeから取得を試みるか、
            ' 監査不能としてエラーを返すべき設計にする
            w = 0: h = 0
    End Select
End Sub

' ==============================================================================
' レポート出力:結果をデバッグウィンドウとメッセージボックスに集約
' 実務ではここを Excel 出力や CSV 出力に差し替える
' ==============================================================================
Private Sub OutputAuditReport(results() As AuditResult, errorCount As Long)
    Dim i As Long
    Dim reportMsg As String
    
    If errorCount = 0 Then
        MsgBox "監査完了: すべてのページの用紙設定は正常です。", vbInformation
        Exit Sub
    End If
    
    reportMsg = "【監査警告】" & vbCrLf & errorCount & " 個のページに不一致が見つかりました。" & vbCrLf & vbCrLf
    
    Debug.Print "--- Audit Report Start ---"
    For i = LBound(results) To UBound(results)
        If results(i).IsError Then
            ' デバッグ出力(詳細ログ)
            Debug.Print "Error in [" & results(i).PageName & "]: " & _
                        "Expected(" & results(i).ExpectedWidth & "x" & results(i).ExpectedHeight & ") " & _
                        "Actual(" & results(i).ActualWidth & "x" & results(i).ActualHeight & ")"
            
            ' ユーザーへの概要表示用
            reportMsg = reportMsg & "- " & results(i).PageName & ": " & results(i).Message & vbCrLf
        End If
    Next i
    Debug.Print "--- Audit Report End ---"
    
    MsgBox reportMsg, vbExclamation
End Sub

4. 伝説のアーキテクトからのアドバイス

このコードをベースに、さらに実務へ適応させるための「次の一手」を伝えておく。

外部連携の注意点

もしこの結果を Excel に出力する場合、`Excel.Application` を参照設定して直接操作するのは避けよ。COM参照は動作を重くし、実行環境のバージョン差異によるランタイムエラーを誘発する。
可能であれば、「CSV形式でファイルに書き出す」か、「クリップボードにテキストとしてコピーする」設計にせよ。これが、環境に依存しない「疎結合」な設計である。

拡張性の確保

今回、`GetExpectedDimensions` 内で `Select Case` を用いて寸法をハードコーディングした。これは小規模なら許容されるが、大規模なプロジェクトでは、このマッピングデータ自体を 外部の構成ファイル(JSONやXML) または データベース から読み込むように設計変更せよ。用紙規格の追加に際して、VBAのロジック(コード)を触らなくて済む状態こそが、真のプロフェッショナルだ。

結論

自動化ツールを作る際、我々は「コードを書いている」のではない。「業務の品質を担保する仕組みを構築している」のだ。
単なるプロパティの参照で満足するな。その値が持つ「意味」を読み解き、エラーの予兆を捉える。それこそが、エンジニアリングの本質である。

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