7年ほど前に、Acrobatを使わず、Adobe Readerで表示したPDFファイルからページ数を取得するマクロについて記事を書きました。
上記記事でも書いてある通り、バージョン依存で不安定、かつ冗長な処理なので、決してお薦めできるものではないのですが、先日Adobeのフォーラムで、上記コードに関わるスレッドを見つけました。
まさかこのコードを使用している方が居られるとは・・・。
質問としては、Adobe ReaderのバージョンをDCにしたところマクロが動作しなくなったというものなのですが、プロパティダイアログを表示するメニューIDやダイアログの構造などが変更されているので、それはそうだろうと思います。
今回は、実用的ではないことを承知で、Acrobat Reader DCに対応した、PDFファイルのページ数を取得するマクロを書いてみました。
'※64ビット版Officeで実行する場合は要コード変更 'UIAutomationClient(UIAutomationCore.dll)要参照 Option Explicit Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Const WM_COMMAND As Long = &H111 Public Sub Sample() Dim num As Long Const PDFPath As String = "C:\Test\T e s t.pdf" num = GetPDFNumPagesUsingAdobeReader(PDFPath) MsgBox "[" & PDFPath & "]ファイルのページ数:" & num, vbInformation + vbSystemModal End Sub Private Function GetPDFNumPagesUsingAdobeReader(ByVal PDFPath As String) As Long 'Adobe Readerの[文書のプロパティ]ダイアログからPDFのページ数を取得 Dim uiAuto As CUIAutomation Dim elmApp As IUIAutomationElement Dim elmRoot As IUIAutomationElement Dim elmDialog As IUIAutomationElement Dim elmTabItem As IUIAutomationElement Dim elmTextPageNumCaption As IUIAutomationElement Dim elmTextPageNum As IUIAutomationElement Dim elmButtonCancel As IUIAutomationElement Dim elmButtonClose As IUIAutomationElement Dim ptnSel As IUIAutomationSelectionItemPattern Dim ptnInvoke As IUIAutomationInvokePattern Dim hApp As Long Dim readerPath As String Dim ret As Long 'Adobe Readerで指定したPDFファイルを表示 readerPath = GetAdobeReaderPath If Len(Trim(GetAdobeReaderPath)) < 1 Then GoTo Fin Shell """" & readerPath & """" & " " & """" & PDFPath & """", vbNormalFocus 'Adobe Reader取得 '※PDF表示まで多少時間が掛かる場合有り Set uiAuto = New CUIAutomation Set elmRoot = uiAuto.GetRootElement Do Set elmApp = GetElement(uiAuto, _ elmRoot, _ UIA_ClassNamePropertyId, _ "AcrobatSDIWindow", _ UIA_WindowControlTypeId) Sleep 200 DoEvents Loop While elmApp Is Nothing '[文書のプロパティ]ダイアログ取得 hApp = elmApp.GetCurrentPropertyValue(UIA_NativeWindowHandlePropertyId) PostMessage hApp, WM_COMMAND, &H1794, 0 '文書のプロパティ表示 Do Set elmDialog = GetElement(uiAuto, _ elmApp, _ UIA_NamePropertyId, _ "文書のプロパティ", _ UIA_WindowControlTypeId) Sleep 200 DoEvents Loop While elmDialog Is Nothing '[概要]タブ選択 Set elmTabItem = GetElement(uiAuto, _ elmDialog, _ UIA_NamePropertyId, _ "概要", _ UIA_TabItemControlTypeId) If elmTabItem Is Nothing Then GoTo Fin Set ptnSel = elmTabItem.GetCurrentPattern(UIA_SelectionItemPatternId) ptnSel.Select '[ページ数]取得 Set elmTextPageNumCaption = GetElement(uiAuto, _ elmDialog, _ UIA_NamePropertyId, _ "ページ数 :", _ UIA_TextControlTypeId) If elmTextPageNumCaption Is Nothing Then GoTo Fin Set elmTextPageNum = uiAuto.RawViewWalker.GetNextSiblingElement(elmTextPageNumCaption) If elmTextPageNum Is Nothing Then GoTo Fin ret = CLng(elmTextPageNum.CurrentName) 'ダイアログを閉じてアプリケーション終了 Set elmButtonCancel = GetElement(uiAuto, _ elmDialog, _ UIA_NamePropertyId, _ "キャンセル", _ UIA_ButtonControlTypeId) If elmButtonCancel Is Nothing Then GoTo Fin Set ptnInvoke = elmButtonCancel.GetCurrentPattern(UIA_InvokePatternId) ptnInvoke.Invoke Set elmButtonClose = GetElement(uiAuto, _ elmApp, _ UIA_NamePropertyId, _ "閉じる", _ UIA_ButtonControlTypeId) If elmButtonClose Is Nothing Then GoTo Fin Set ptnInvoke = elmButtonClose.GetCurrentPattern(UIA_InvokePatternId) ptnInvoke.Invoke Fin: GetPDFNumPagesUsingAdobeReader = ret End Function Private Function GetAdobeReaderPath() 'Adobe Reader(AcroRd32.exe)のパスを取得 Dim folderPath As String Dim filePath As String Dim itm As Object Const ExeName As String = "AcroRd32.exe" '[プログラムと機能]からAdobe Readerのインストール先フォルダを取得 With CreateObject("Shell.Application").Namespace("shell:::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}") For Each itm In .Items If InStr(LCase(itm.Name), "adobe") And InStr(LCase(itm.Name), "reader") Then '[Extended Asian Language font pack]は除外 If InStr(LCase(itm.Name), "extended") < 1 Then folderPath = .GetDetailsOf(itm, 10) Exit For End If End If Next End With 'Adobe Readerのパスを取得 With CreateObject("Scripting.FileSystemObject") filePath = .BuildPath(folderPath, "Reader") filePath = .BuildPath(filePath, ExeName) If .FileExists(filePath) = True Then GetAdobeReaderPath = filePath End With End Function Private Function GetElement(ByVal uiAuto As CUIAutomation, _ ByVal elmParent As IUIAutomationElement, _ ByVal propertyId As Long, _ ByVal propertyValue As Variant, _ Optional ByVal ctrlType As Long = 0) As IUIAutomationElement Dim cndFirst As IUIAutomationCondition Dim cndSecond As IUIAutomationCondition Set cndFirst = uiAuto.CreatePropertyCondition( _ propertyId, _ propertyValue _ ) If ctrlType <> 0 Then Set cndSecond = uiAuto.CreatePropertyCondition( _ UIA_ControlTypePropertyId, _ ctrlType _ ) Set cndFirst = uiAuto.CreateAndCondition( _ cndFirst, _ cndSecond _ ) End If Set GetElement = elmParent.FindFirst(TreeScope_Subtree, cndFirst) End Function
処理の流れは下記の通りで、UI Automationを使って、アプリケーションやダイアログの操作を行っています。
- 「プログラムと機能」からAdobe Readerのパスを取得する。
- Adobe ReaderでPDFファイルを開く。
- 文書のプロパティダイアログを表示する。
- 文書のプロパティダイアログからページ数を取得する。
- 文書のプロパティダイアログを閉じる。
- Adobe Readerを終了する。
重ねて言いますが、上記コードは、バージョン依存であまり実用的ではないので、本家AcrobatやサードパーティのiTextSharp、CPDF(Coherent PDF)といったツールを使える環境であれば、そちらを使うことをお薦めします。
この記事へのコメントはありません。