|||||||||||||||||||||

なんぶ電子

- 更新: 

WordのVBAでフォントの存在チェック

VBA Wordフォントチェックツール

MS Wordを使っていて、作成したのと別の環境で表示したときと比べてレイアウトが崩れてしまう原因のひとつにフォントがあります。ドキュメント内で指定されているフォントがないと、実際とは違うフォントで線画されるため、意図したフォントで表示されないだけでなく場合によってレイアウトが崩れたりします。

そこでフォントをチェックするツールをVBAで作成しようというのが今回の話です。すこし古いOffice2013 Word環境でコーディングしましたが、最新の2019での稼働が確認できました。

開発の表示と参照設定

まず環境の構築をします。Wordの開発タブが表示されていない場合は「開発タブを出します」「ファイル」→「オプション」から「リボンのユーザー設定」から右側のタブの「開発」にチェックを入れます。

開発タブを表示

次に表示した開発タブから「Visual Vasic」を選択し表示された画面の「ツール」から「参照設定」を開き「Microsoft Scripting Runtime」と「Microsoft XML, V6.0」を選択します。前者はファイル操作用、後者はXML読み込み用のライブラリとなっています。画像では選択されて上段にきていますが、選択されていない際は下の方に該当の項目が存在します。

VBAの参照設定

メインとなるコード

先にメインとなるコードを紹介します。このコードはおおむね次のように流れていきます。

  1.  

    まず、使っている環境で利用で利用できるフォントをリストアップします。VBAで既存のフォントを確認するには、「Application.FontNames」を使います。

    これで得られるフォント名の中には@から始まるものがあります。これらは縦書き用のフォントなので今回は取得対象外としています。

  2.  

    次にチェックするドキュメントのフォントを取得します。詳しくは後述しますが、WordドキュメントをZIPファイルとして展開した際に出力されるXMLを読み込むことで利用しているフォントのリストを取得しています。

  3.  

    最後にふたつのフォントリストを照らし合わせて不足している場合にメッセージに表示します。

ソースは次のようになっています。この関数の引数としてチェックしたいWordドキュメントを渡します。

checkFonts

Private Sub checkFonts(doc As Document)
     
    Dim strFonts() As String
    Dim strDocFonts() As String
    
    Dim i, j As Integer
    Dim intFontCnt As Integer
    Dim blnExist As Boolean
    Dim strMsg As String
    Dim fs As New FileSystemObject
    Dim strWorkDir As String
    
    '既存フォント取得
    intFontCnt = 0
    For i = 1 To Application.FontNames.Count
        If Left(Application.FontNames.Item(i), 1) <> "@" Then
            intFontCnt = intFontCnt + 1
        End If
    Next i
    
    ReDim strFonts(intFontCnt - 1)
    For i = 1 To Application.FontNames.Count
        If Left(Application.FontNames.Item(i), 1) <> "@" Then
            strFonts(i - 1) = Application.FontNames.Item(i)
        End If
    Next i
    
    'ドキュメントのフォント取得
    '一時フォルダで作業します
    strWorkDir = fs.GetSpecialFolder(TemporaryFolder) & "\get-fonts-work"
    
    'ワークフォルダ作成(スクラップ&ビルド)
    If fs.FolderExists(strWorkDir) Then
        fs.DeleteFolder strWorkDir
    End If
    fs.CreateFolder strWorkDir
    
    'サブフォルダ
    fs.CreateFolder strWorkDir & "\extract"
    
    'ファイルをワーク領域にコピー
    fs.CopyFile doc.Path & "\" & doc.Name, strWorkDir & "\temp.zip", True
    
    'ファイルを展開
    unzip strWorkDir & "\temp.zip", strWorkDir & "\extract"
    
    'XMLからフォント取得
    strDocFonts = getDocFonts(strWorkDir & "\extract" & "\word\fontTable.xml")
    
    
    '比較
    For i = 0 To UBound(strDocFonts)
        
        blnExist = False
        
        For j = 0 To UBound(strFonts)
            If strDocFonts(i) = strFonts(j) Then
                blnExist = True
                Exit For
            End If
        Next j
        
        If blnExist = False Then
            strMsg = strMsg & vbCrLf & strDocFonts(i)
        End If
        
    Next i
        
    'ワークフォルダ片付け
    fs.DeleteFolder strWorkDir
     
    Set fs = Nothing

    If strMsg = "" Then
        Debug.print "すべてのフォントが利用できます"
    Else
        strMsg = doc.Name & "内の次のフォントが利用できません" & strMsg
        Debug.print strMsg
    End If
    
End Sub

ドキュメント内で利用しているフォントを取得

ドキュメント内で利用しているフォントを取得する方法はWord:「使用されているフォント 一覧を表示する方法」を参考にさせていただきました。

一度ZIPファイルとして展開して、中にあるフォント一覧のあるXMLファイルを読み込みます。この時一時フォルダを作業スペースとして利用しました。

まず調べたいファイルを一時フォルダにコピーします。

コピーしたファイルを展開します。これにはPowerShellを利用しています。この方法はExcel作業をVBAで効率化:「VBAでZIP圧縮と解凍を行う」を参考にさせていただきました。

またWScriptの操作ではQuiita:「VBAからPowerShellを起動し、任意コマンドを実行する」を参考にさせていただきました。

unzip

Private Function unzip(strSource As String, strTarget As String)
    
    Dim objWSH As Object
    Dim blnWait As Boolean
    Dim intVisibleType As Integer '0:off 1:on
    Dim strCommand As String
    
    blnWait = True
    intVisibleType = 0
    
    strCommand = "Expand-Archive -Path " & strSource & " -DestinationPath " & strTarget & " -Force"
    
    Set objWSH = CreateObject("WScript.Shell")
    
    objWSH.Run "powershell -NoLogo -ExecutionPolicy RemoteSigned -Command " & strCommand, intVisibleType, blnWait

End FunctionEnd Sub

XMLをParse

先の参考サイトにあったようにWordファイルをZIPファイルとみなして展開して出てくる&yen;word&yen;fontTable.xmlを読み込みます。中身は割とシンプルなのでXMLでparseしないでテキストで読み込んでもいいかなとコードを書いた後で思いました。

XMLのパースについてはプログラマー向けEXCEL活用術ブログ:「【VBA】ノード名を指定せずにXMLをパースする」を参考にさせていただきました。

この関数の引数にはfontTable.xmlのパスを渡します。

getDocFonts

Private Function getDocFonts(strPath As String) As String()
    
    Dim XMLDocument As New MSXML2.DOMDocument60
    Dim nodeFonts As IXMLDOMNode
    Dim node As IXMLDOMNode
    Dim intCnt As Integer
    Dim strFonts() As String
    
    XMLDocument.async = False
    
    XMLDocument.Load strPath
        
    If (XMLDocument.parseError.ErrorCode <> 0) Then
        'XMLParseエラー
        getDocFonts = strFonts
        Exit Function
        
    End If
    
    Set nodeFonts = XMLDocument.ChildNodes(1)
    
    intCnt = 0
    
    'fontsの子ノードがfont
    For Each node In nodeFonts.ChildNodes
        If node.Attributes(0).NodeValue <> "" Then
            intCnt = intCnt + 1
        End If
    Next node
    
    ReDim strFonts(intCnt - 1)
    intCnt = 0
    For Each node In nodeFonts.ChildNodes
        If node.Attributes(0).NodeValue <> "" Then
            strFonts(intCnt) = node.Attributes(0).NodeValue
            intCnt = intCnt + 1
        End If
    Next node

    Set node = Nothing
    Set nodeFonts = Nothing
        
    getDocFonts = strFonts
    
End Function

どのファイルを開いてもコードが使えるように

コードを記述したファイルを使うたびにオープンするのは何となくスマートではありません。なので、このコードをWordの共通データに保存します。

「開発」「マクロ」のウインドウを開き、中段にある「マクロの保存先」を「Normal.dotm(全文書対象のテンプレート)」に切り替え右側の「構成内容変更」ボタンを押します。

開いたウインドウの左側がマクロを作成したファイル、右側が共通のテンプレートとなります。右側の一覧から共通にさせたいマクロが含まれるモジュールや、フォームを右側にコピーします。

一度登録したものを削除したい場合は、右側の一覧の中から対象のモジュールやフォームを選択した状態で削除を押します。

コピーした後は「閉じる」を押して終了させてください。これでどのファイルからもマクロを呼び出せるようになりました。

マクロやフォームをどのファイルからも利用可能にする

参考にさせていただきましたサイトの皆様ありがとうございました

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告