スタイル

カスタムドキュメントプロパティを利用する

アドインやテンプレートにユーザー設定を保存したい場合、どこに保存するのかが問題になります。VBAアセットでは、「VA公用文」(Word VBA)の開発過程から得られた経験を踏まえ、カスタムドキュメントプロパティを利用することをそのスタイルとしています。

設定保存方法の変遷

アドインとして使用することを想定した「VA公用文」の開発では、ユーザー設定の保存方法について改善を重ねてきました。

第一段階:アドインファイルのドキュメント自体に保存(Ver.7D1以前)

初期バージョンでは、設定値をアドインファイル(.dotm)内のWordドキュメント本体に、次のようにして直接書き込んでいました。

この方法で実際に問題が生じたことはなかったのですが、ユーザーが予期しない内容に設定値を書き換えてしまったり、Wordの自動保存や復元機能で予期しない不具合を発生させたりするのではないかという不安がありました。

第二段階:外部設定ファイル(.ini)への移行(Ver.800~840)

Ver.8では、プログラムの安定性を高めるため、設定値を外部ファイル「VA公用文.ini」に分離し、次のようにして保存するように変更しました。

' ファイルパスを生成
filePath = Application.StartupPath & Application.PathSeparator & strSettingsFileName

--- 以下省略 ---

この外部ファイル方式により、ドキュメント本体への書き込みによる不安が解消され、Windows環境では安定して動作することが確認できていました。ところが、Mac環境では動作しなくなってしまったのです。

その主な原因は、権限の欠如でした。macOSでは、Officeアプリケーションの起動フォルダ(StartupPath)はシステムに近い保護された領域に位置しており、マクロからファイルを書き込む権限が与えられていないのです。さらに、代替策としてユーザーのホームディレクトリに保存しようとしても、Mac環境では Environ("USERPROFILE")Environ("HOME") が空文字列を返す場合があり、パスの特定自体が困難でした。

最終解決策:カスタムドキュメントプロパティの利用(Ver850以降)

このような状況が生じていることをAI(Gemini)に入力して、解決策を検討させたところ、回答として得られたのが、Office製品に標準搭載されているカスタムドキュメントプロパティの利用でした。

カスタムドキュメントプロパティであれば、設定値がOfficeファイル形式の内部にメタデータとして格納されるため、OSのファイルシステムやパス構造に一切依存しないようです。また、VBAコードが格納されているアドインファイル自体に対しては、アプリケーションが常に読み書きの権限を持っているため、外部ファイルへの書き込み制限を気にする必要がないようです。

カスタムドキュメントプロパティの利用法

保存処理(Word VBA)

'==============================================================================
' 機能: キーと値の配列の内容を、アドインファイル(ThisDocument)の
'       カスタムドキュメントプロパティとして保存します。
'       保存後、アドインファイルを明示的に保存します。
'------------------------------------------------------------------------------
' 引数:
'   ByRef varKeys() As Variant: 設定のキー名(プロパティ名)を含む配列。
'   ByRef varValues() As Variant: 設定の値(プロパティ値)を含む配列。
' 注意:
'   varKeys と varValues の LBound, UBound は一致している必要があります。
'==============================================================================
Public Sub SaveSettingsToProperty(ByRef varKeys() As Variant, ByRef varValues() As Variant)
    Dim i As Long
    Dim doc As Document
    Dim keyName As String
    Dim prefixedKeyName As String
    Dim propType As Long
    Dim prop As DocumentProperty
    
    ' プロシージャを実行しているアドインファイル自身を参照
    Set doc = ThisDocument
    
    ' 配列の要素数が一致しない場合はエラー (LBoundもチェック)
    If LBound(varKeys) <> LBound(varValues) Or UBound(varKeys) <> UBound(varValues) Then
        MsgBox "キーと値の配列のインデックス範囲が一致しません。", vbCritical
        GoTo CleanExit
    End If
    
    On Error GoTo SaveError
    
    For i = LBound(varKeys) To UBound(varKeys)
        keyName = varKeys(i)
        prefixedKeyName = c_Prefix & keyName ' プレフィックスを付加
        
        ' 値の型に応じてプロパティの型を決定
        Select Case VarType(varValues(i))
            Case vbInteger, vbLong
                propType = msoPropertyTypeNumber
            Case vbSingle, vbDouble, vbCurrency
                propType = msoPropertyTypeFloat
            Case vbDate
                propType = msoPropertyTypeDate
            Case vbBoolean
                propType = msoPropertyTypeBoolean
            Case Else ' vbString, vbEmpty, vbNull, etc.
                propType = msoPropertyTypeString
        End Select
        
        ' 既存のプロパティを検索
        On Error Resume Next
        Set prop = doc.CustomDocumentProperties(prefixedKeyName)
        
        If Err.Number <> 0 Then
            ' プロパティが存在しない場合:新規作成
            Err.Clear
        Else
            ' プロパティが存在する場合:更新
            ' 型の不一致エラーを避けるため、一度削除する
            prop.Delete
        End If
        
        ' プロパティを(再)追加
        doc.CustomDocumentProperties.Add _
            Name:=prefixedKeyName, _
            LinkToContent:=False, _
            Type:=propType, _
            value:=varValues(i)
            
        On Error GoTo SaveError ' エラー処理を元に戻す
    Next i
    
    ' Wordにファイルに変更があったことを明示的に通知する
    doc.Saved = False
    
    ' 変更を保存するために、アドインファイルを明示的に保存する
    doc.Save
    
    GoTo CleanExit

SaveError:
    MsgBox "設定値の保存に失敗しました。" & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical
           
CleanExit:
    ' オブジェクトを解放
    Set doc = Nothing
    Set prop = Nothing
End Sub

読み込み処理(Word VBA)

'==============================================================================
' 機能: アドインファイル(ThisDocument)のカスタムドキュメントプロパティから
'       このモジュールが管理する設定値(プレフィックス付き)のみを読み込み、
'       キーと値の配列に格納します。
'------------------------------------------------------------------------------
' 引数:
'   ByRef varKeys() As Variant: 読み込んだ設定のキー名(プレフィックス除去後)を格納する配列。
'   ByRef varValues() As Variant: 読み込んだ設定の値(プロパティ値)を格納する配列。
'==============================================================================
Public Sub LoadSettingsFromProperty(ByRef varKeys() As Variant, ByRef varValues() As Variant)
    Dim doc As Document
    Dim prop As DocumentProperty
    Dim tempKeys() As Variant
    Dim tempValues() As Variant
    Dim count As Long
    Dim i As Long
    Dim prefixLen As Long
    
    ' プロシージャを実行しているアドインファイル自身を参照
    Set doc = ThisDocument
    
    ' 配列を初期化
    Erase varKeys
    Erase varValues
    count = 0
    prefixLen = Len(c_Prefix)
    
    On Error GoTo LoadError
    
    ' プレフィックスに一致するプロパティの数を先に数える
    For Each prop In doc.CustomDocumentProperties
        If Left(prop.Name, prefixLen) = c_Prefix Then
            count = count + 1
        End If
    Next prop
    
    If count = 0 Then GoTo CleanExit ' 該当プロパティなし
    
    ' 配列のサイズを一度だけ確保 (1ベース配列)
    ReDim tempKeys(1 To count)
    ReDim tempValues(1 To count)
    
    i = 1
    ' 再度ループして、該当するキーと値を配列に格納
    For Each prop In doc.CustomDocumentProperties
        If Left(prop.Name, prefixLen) = c_Prefix Then
            ' プレフィックスを除去したキー名
            tempKeys(i) = Mid(prop.Name, prefixLen + 1)
            tempValues(i) = prop.value
            i = i + 1
            If i > count Then Exit For ' 念のため (count分取得したら抜ける)
        End If
    Next prop
    
    ' 結果を引数に代入
    varKeys = tempKeys
    varValues = tempValues
    
    GoTo CleanExit
    
LoadError:
    MsgBox "設定値の読み込みに失敗しました。" & vbCrLf & _
           "エラー内容: " & Err.Description, vbCritical

CleanExit:
    ' オブジェクトを解放
    Set doc = Nothing
    Set prop = Nothing
    Erase tempKeys
    Erase tempValues
End Sub

実際の利用方法は、こちらをご確認ください。

参考:VBAを使わずに設定値を確認・編集する

カスタムドキュメントプロパティは、次の手順でVBAを使わずに直接確認・編集することもできます。

  1. 対象のアドインファイルを開く
  2. 「ファイル」タブ →「情報」に移動
  3. 右側の「プロパティ」ドロップダウンをクリック
  4. 「詳細プロパティ…」を選択
  5. 「ユーザー設定」タブをクリック

コメント

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