Acrobat OLEのエラーを防ぐVBAロジック

TOP > *


Good Smile Racing -Wonder Festival 2015 [Summer] (Makuhari, Chiba, Japan)

 

概要

Acrobat OLE+VBAプログラミング時のエラー回避方法を紹介します。大量のPDFを連続で処理する事を前提にしています。内容は多いです。

用語:

  • Acrobat OLE : VBAプログラミング内で使うAcrobat OLE(IAC)の変数や命令(メソッド)の事
  • Acrobatプロセス : メモリ上のAcrobatアプリケーション(Acrobat.exe)の事。Acrobat OLEを動かすとコレが立ち上がります。
  • Acrobatアプリケーション : デスクトップ上に表示されるAcrobatソフトの事

目次:

  1. 概要 ※ココ
  2. エラーの種類
  3. 連続処理のやり方
  4. エラー処理を入れたサンプル
  5. Acrobatプロセスの監視
  6. Acrobat OLE変数の宣言
  7. Acrobat OLE変数の宣言場所
  8. Acrobat OLE変数の宣言は一箇所のみ
  9. Acrobat OLEの終了
  10. Acrobat OLE変数の引数での使用
  11. Acrobatプロセスのチェック
  12. Acrobatプロセスに優しい終了
  13. Acrobatプロセスの強制終了
  14. Acrobatプロセスをメモリ上に強制的に乗せる+AFormAutエラー対策
  15. VBAランタイムエラーの対処
  16. Windowsの再起動
  17. Windows 11+MS Excel 2021
  18. 備考

エラーの種類

以下のエラーを出てしまう事が有ります。

  1. PDFファイルを開いたままで終了してしまった。
    • 原因:ロジックのミス
  2. 処理は全て終わったのにメモリ上からAcrobatプロセスが消えない。
    • 原因1:ロジックのミス。処理途中のAcrobat OLEオブジェトが残る
    • 原因2:VBAのCallByName関数でAcrobat OLEを使用した
    • 原因3:PCのスペックによる。メモリからプロセスが消えるのに数秒は掛かる場合があります。サイト管理人の非力PCでは最低6秒掛かります。数千件の連続処理を行うと10秒以上も掛かる。
  3. 「・・オブジェクトを作成できません。」エラーメッセージが出る。
    • 原因:詳細は不明。メモリ上にAcrobatプロセスの何か・・が足りないからと予測しています。

対処方法です。これ以外にエラーを減らす工夫も入れてます。

連続処理のやり方

2種類有ります。以下の2つのサンプルを見て下さい。。

サンプル1:

推奨です。処理したいPDFファイルのパスを配列で渡して、Loop_1内でループ(For ~ Next)処理します。

サンプル1(推奨):PDFを連続でAcrobat OLEを利用して処理する。
  • メリット
    1. Acrobat OLE変数の定義もAcrobat OLE終了の処理も一回しか行わない。
    2. Sub Loop_1 内でAcrobat OLEの処理が全て含まれている。
    3. PCへの負荷を少ない。
    4. Acrobat OLEエラーが出にくい・・と思う。
  • デメリット
    1. Loop_1のロジックが長くなる。
    2. Loop_1のループ内でのエラー処理が複雑になる。

サンプル2:

非推奨です。Loop_2はPDFファイルの数だけ呼ばれます。連続処理では出来れば避けて欲しいです。

サンプル2(非推奨):PDFを連続でAcrobat OLEを利用して処理する。
  • メリット
    1. ロジックが組みやすい。
    2. 他に流用しやすい。
    3. エラー処理がシンプル。
  • デメリット
    1. Acrobat OLE関連の処理がPDFファイル毎に全て実行されます。
    2. CPUの処理量が多い。処理時間が少し長くなる。システム負荷が多くなる。つまり動作不安定になる可能性が有る。

連続で無い場合はサンプル2がお勧めです。

エラー処理を入れたサンプル

以下の3種のエラーに対処したサンプルです。

  1. Acrobat OLEエラー
  2. VBA実行時のランタイムエラー
  3. デバッグ時の操作エラー、及び中断等

サンプルの処理内容です。

  • Acrobat OLEでAcrobat JavaScriptを実行してPDFからブックマーク(しおり)を階層と頁番号を付けて抽出します。
  • 抽出の結果はテキストファイルへ出力
  • 途中の経過もテキストファイルへ出力
  • エラー時はその内容も同じテキストファイルへ出力

行番号は見やすくする為に追加で表示しているだけです。行番号の色はエラー対応で追加した部分です。

  • 黄色:Acrobat OLEのエラー対応
  • マゼンダ:VBA実行時のランタイムエラー対応
  • 緑色:デバッグ時の操作エラー対応

エラー対応が混ざっている箇所も有ります。半分がエラー処理・・です。

001 Option Explicit 002 003 Private msMsg As String 'メッセージ 004 Private miErrorCnt As Long 'エラー数 005 Private Const CON_ERROR_CNT As Long = 10 006 ' テキストファイルの出力用 007 Private msLogFilePath As String 'LOGのファイルパス 008 Private miLogFileNo As Long 'LOGのファイルNO 009 Private msText As String 'LOGのメッセージ 010 ' VBA RunTime Error 対応用 011 Private miErrorNo As Long 'Err.Number の内容 012 Private msErrorMsg As String 'Err.Description の内容 013 014 '********************************************* 015 ' Main ココからスタート 016 '********************************************* 017 Sub Main() 018 '初期化 019 msMsg = "" 020 miErrorNo = 0 021 miErrorCnt = 0 022 miLogFileNo = 0 023 Call PutTextlog("Start") 'VBA開始 024 025 '▼メモリ上のAcrobatプロセスを確認する 026 If iCheckAcrobat() > 0 Then 027 msMsg = "Acrobatが動いています。" _ 028 & vbCrLf & "処理を中断します。" & vbCrLf _ 029 & vbCrLf & "この後でAcrobatの終了を試みます。" 030 MsgBox msMsg, vbCritical, "実行の中断" 031 'Acrobat OLEの終了を試みる 032 Call EndAcrobat 033 Exit Sub 034 End If 035 036 Dim i As Long 037 Dim sPDF(2) As String 038 sPDF(0) = "D:\work\Test01.PDF" 039 sPDF(1) = "D:\work\Test02.PDF" 040 sPDF(2) = "D:\work\Test04.PDF" 041 042 '▼PDFファイルの処理 043 Call Get_Siori(sPDF) 044 045 '▼画面に終了メッセージ表示 046 If (msMsg = "") And (miErrorCnt = 0) Then 047 msMsg = Date & " " & Time & vbCrLf & _ 048 "正常終了しました。" 049 MsgBox msMsg, vbInformation, "完了" 050 Else 051 If msMsg = "" Then msMsg = "実行時にエラーが有りました。" 052 msMsg = Date & " " & Time & vbCrLf & msMsg _ 053 & vbCrLf & "ログファイルも見て下さい。" 054 MsgBox msMsg, vbCritical, "実行の中断" 055 Call PutTextlog("Error" & vbCrLf & msMsg) 056 End If 057 Call PutTextlog("End") 'VBA終了 058 End Sub 059 '********************************************* 060 ' PDFからしおりを抽出 061 ' 内部でLoopして複数のPDFを一括で処理する。 062 '********************************************* 063 Sub Get_Siori(ByRef sPDF() As String) 064 On Error GoTo Skip_RTError: 'VBAランタイムエラー 065 Dim i As Long 066 Dim bRet As Boolean 067 Dim sRet As String 068 'Acrobat JavaScript:階層+頁番号+しおりの抽出 069 Const sAJS As String = _ 070 "function DumpBookmark(bm, nLevel){" & vbCrLf & _ 071 " var s='';" & vbCrLf & _ 072 " for (var i=0;i<nLevel;i++) s+=' ';" & vbCrLf & _ 073 " if (i==0){" & vbCrLf & _ 074 " n=this.numPages-1" & vbCrLf & _ 075 " }else{" & vbCrLf & _ 076 " bm.execute(); " & vbCrLf & _ 077 " n=this.pageNum" & vbCrLf & _ 078 " }" & vbCrLf & _ 079 " p+=(s+'\r\n'+('00'+i).slice(-2)+','+ " & vbCrLf & _ 080 " ('0000'+(n+1)).slice(-4)+'+-'+ " & vbCrLf & _ 081 " bm.name);" & vbCrLf & _ 082 " if (bm.children!=null)" & vbCrLf & _ 083 " for (var i=0;i<bm.children.length;i++)" & vbCrLf & _ 084 " DumpBookmark(bm.children[i],nLevel+1);" & vbCrLf & _ 085 "}" & vbCrLf & _ 086 "var p='';" & vbCrLf & _ 087 "DumpBookmark(this.bookmarkRoot,0);" & vbCrLf & _ 088 "event.value = p;" 089 090 'Acrobat OLE 変数の宣言 091 Dim objAcroApp As New Acrobat.AcroApp 092 Dim objAcroAVDoc As New Acrobat.AcroAVDoc 093 Dim objAFormApp As New AFORMAUTLib.AFormApp 094 Dim objAFormFields As AFORMAUTLib.Fields 095 '※この時点ではメモリ上に出て来ない 096 097 'Acrobat OLEをメモリに先に乗せる為 098 objAcroApp.CloseAllDocs '開いているPDFを全て閉じる 099 objAcroApp.Hide '稀に表示したら隠す 100 101 For i = 0 To UBound(sPDF) 102 sRet = "" 103 msText = "開始 (" & (i + 1) & _ 104 ") """ & sPDF(i) & """" 105 Call PutTextlog(msText) 106 If miErrorNo <> 0 Then GoTo Skip_RTError: 107 108 If Dir(sPDF(i)) = "" Then 109 msText = "Error-1:ファイルが存在しない。" 110 Call PutTextlog(msText) 111 If miErrorNo <> 0 Then GoTo Skip_RTError: 112 miErrorCnt = miErrorCnt + 1 113 GoTo Skip_Loop_Next: 114 End If 115 116 'PDFのOpen処理 117 bRet = objAcroAVDoc.Open(sPDF(i), "") 118 If bRet = False Then 119 msText = "Error-2:Open出来なかった。" 120 Call PutTextlog(msText) 121 If miErrorNo <> 0 Then GoTo Skip_RTError: 122 miErrorCnt = miErrorCnt + 1 123 GoTo Skip_Loop_Next: 124 End If 125 126 'Acrobat JavaScriptを実行して、しおりを抽出 127 Set objAFormFields = objAFormApp.Fields 128 sRet = objAFormFields.ExecuteThisJavascript(sAJS) 129 If sRet = "" Then 130 msText = "Error-3:しおり抽出が失敗した。" 131 Call PutTextlog(msText) 132 If miErrorNo <> 0 Then GoTo Skip_RTError: 133 miErrorCnt = miErrorCnt + 1 134 GoTo Skip_Get_Close: 135 End If 136 137 'しおりをテキストファイルへ出力 138 Call PutTextSiori(sRet, sPDF(i)) 139 If miErrorNo <> 0 Then GoTo Skip_RTError: 140 141 Skip_Get_Close: 142 '保存しないでClose 143 bRet = objAcroAVDoc.Close(0) 144 If bRet = False Then 145 msText = "Error-4:Close出来なかった。" 146 Call PutTextlog(msText) 147 If miErrorNo <> 0 Then GoTo Skip_RTError: 148 miErrorCnt = miErrorCnt + 1 149 GoTo Skip_Loop_Next: 150 End If 151 152 If sRet <> "" Then msText = "完了" 153 Call PutTextlog(msText) 154 If miErrorNo <> 0 Then GoTo Skip_RTError: 155 Skip_Loop_Next: 156 If miErrorCnt > CON_ERROR_CNT Then 157 msText = "Error-5:エラーが" & CON_ERROR_CNT & _ 158 "件を超えたので処理を中断します。" 159 Call PutTextlog(msText) 160 If miErrorNo <> 0 Then GoTo Skip_RTError: 161 msMsg = msText 162 GoTo End_Exit: 163 End If 164 Next i 165 GoTo End_Exit: 166 167 ' ------------------------------------ 168 '▼Acrobat OLEのエラー処理 169 Skip_OLE_Error: 170 On Error Resume Next 171 msMsg = msText '& vbCrLf & sPDF(i) 172 msText = msText & " " & sPDF(i) 173 Call PutTextlog(msText) 174 If miErrorNo <> 0 Then GoTo Skip_RTError: 175 bRet = objAcroAVDoc.Close(0) 176 msMsg = """" & msMsg & """" & vbCrLf & _ 177 "OLEのエラーで処理が中断しました。" 178 GoTo End_Exit: 179 180 ' ------------------------------------ 181 '▼VBAのランタイムエラー処理 182 Skip_RTError: 183 msMsg = Err.Number & "/" & Err.Description 184 If miErrorNo <> 0 Then 185 msMsg = "★VBA ランタイムエラー発生!★" & _ 186 vbCrLf & """" & miErrorNo & " " & _ 187 msErrorMsg & """" 188 End If 189 On Error Resume Next 190 msMsg = msMsg & vbCrLf & _ 191 "上記のエラーで処理中断しました。" & _ 192 vbCrLf & sPDF(i) 193 Call PutTextlog(msMsg) 194 195 ' ------------------------------------ 196 End_Exit: 197 '▼Acrobat OLEの終了 198 On Error Resume Next 199 'これ以降は無条件に全て強制実行 200 objAcroApp.CloseAllDocs 201 objAcroApp.Hide 202 objAcroApp.Exit 203 'オブジェクトの強制開放 204 Set objAFormFields = Nothing 205 Set objAFormApp = Nothing 206 Set objAcroAVDoc = Nothing 207 Set objAcroApp = Nothing 208 'ここでメモリ上から消える。 209 End Sub 210 '********************************************* 211 ' しおりのテキストファイルの出力 212 '********************************************* 213 Private Sub PutTextSiori(ByVal sText As String, _ 214 ByRef sPDF As String) 215 On Error GoTo Skip_PutTextSiori: 'VBA実行時エラー 216 Dim sDir As String 217 Dim iFileNo As Long 'ファイルNO 218 Dim sFile() As String '作業用 219 Dim sWk As String '作業用 220 Dim sOut As String '作業用 221 222 sDir = ThisWorkbook.Path & "\out" 223 If Dir(sDir, vbDirectory) = "" Then 224 '出力フォルダの作成 225 MkDir sDir 226 End If 227 sFile = Split(sPDF, "\") 228 sWk = sFile(UBound(sFile)) 229 sWk = Left(sWk, Len(sWk) - 4) & ".txt" 230 iFileNo = FreeFile 231 Open (sDir & "\" & sWk) For Output As #iFileNo 232 sOut = Format(Date, "yyyy/mm/dd") _ 233 & Format(Time, " hh:mm:ss") _ 234 & vbCrLf & sPDF 235 Print #iFileNo, sOut 236 Print #iFileNo, sText 237 Close #iFileNo 238 Exit Sub 239 Skip_PutTextSiori: 240 miErrorNo = Err.Number 241 msErrorMsg = Err.Description 242 End Sub 243 '********************************************* 244 ' メモリ上のAcrobatプロセスを数える。 245 '********************************************* 246 Private Function iCheckAcrobat() As Long 247 On Error GoTo skip_iCheckAcrobat: 'VBA実行時エラー 248 Dim items As Object 249 Set items = CreateObject("WbemScripting.SWbemLocator") _ 250 .ConnectServer.ExecQuery( _ 251 "Select * From Win32_Process " & _ 252 "Where Name = 'Acrobat.exe'") 253 '1以上はプロセス有り、0は無し 254 iCheckAcrobat = items.Count 255 Exit Function 256 skip_iCheckAcrobat: 257 miErrorNo = Err.Number 258 msErrorMsg = Err.Description 259 End Function 260 '********************************************* 261 ' ログ・テキストファイルの出力 262 ' ・Excelファイルが有るフォルダに出力する 263 ' ・追加出力する。 264 '********************************************* 265 Private Sub PutTextlog(ByVal sText As String, _ 266 Optional s As String) 267 On Error GoTo Skip_PutTextlog: 'VBA実行時エラー 268 If miLogFileNo = 0 Then 269 '最初に一度だけ実行 270 miLogFileNo = FreeFile 271 msLogFilePath = ThisWorkbook.Path & "\log-" & _ 272 Format(Date, "yyyymmdd-") & _ 273 Format(Time, " hhmmss") & ".txt" 274 End If 275 Open msLogFilePath For Append As #miLogFileNo 276 If s = "" Then 277 sText = Format(Date, "yyyy/mm/dd ") & _ 278 Format(Time, "hh:mm:ss") & _ 279 " " & sText 280 End If 281 Print #miLogFileNo, sText 282 Close #miLogFileNo 283 Exit Sub 284 Skip_PutTextlog: 285 miErrorNo = Err.Number 286 msErrorMsg = Err.Description 287 End Sub 288 '********************************************* 289 ' メモリ上に残ったAcrobatプロセスを 290 ' 正常に終了させる為だけの処理です。 291 '********************************************* 292 Sub EndAcrobat() 293 On Error Resume Next 294 Dim objAcroApp As New Acrobat.AcroApp 295 Dim objAcroAVDoc As New Acrobat.AcroAVDoc 296 Dim objAFormApp As New AFORMAUTLib.AFormApp 297 Dim objAFormFields As AFORMAUTLib.Fields 298 299 objAcroApp.CloseAllDocs 300 objAcroApp.Hide 301 objAcroApp.Exit 302 303 Set objAFormFields = Nothing 304 Set objAcroAVDoc = Nothing 305 Set objAFormApp = Nothing 306 Set objAcroApp = Nothing 307 308 '上記の実行後にメモリ上から消える、はず。 309 MsgBox "Acrobat OLEの終了を試みました。" & _ 310 vbCrLf & "10秒後にメモリから消えたのを" & _ 311 vbCrLf & "タスクマネージャーで確認して下さい。", _ 312 vbSystemModal + vbInformation, "お知らせ" 313 End Sub

 

上記サンプルはAcrobat 8、Acrobat 9では動作しません。動作させたい場合は93~94行目の「AFORMAUTLib.XXXXX」を使わない処理に変更して下さい。詳細は「AFormAut オブジェクト 一覧」の動作確認を御覧ください。

  • Download:  /p1142_get_bookmarks.zip ( 228.6 KB )
  • ファイル名:p1142_get_bookmarks.xls
  • 形式:Excel 97-2003 ブック用

上記サンプルは2つの参照設定(コレコレ)が必要です。  

VBAの参照設定

 

 

Acrobatプロセスの監視

テスト中はタスクマネージャーを起動して、処理が終了したらタスクマネージャーから消えることを確認して下さい。

タスクマネージャーでAcrobatプロセスを監視

メモリに残っていると次の処理で予期せぬ結果になります。その場合は「Adobe Acrobat」プロセスをマウスで右クリックし、「タスクの終了」を実行して下さい。

  

Acrobat OLE変数の宣言

事前にExcelの参照設定をします。AcrobatのバージョンによりVBAでの宣言方法が変わります。

Acrobat ver 4、5、6:

'Acrobat 4,5,6の時 Dim objAcroApp As Acrobat.CAcroApp Dim objAcroAVDoc As Acrobat.CAcroAVDoc Dim objAcroPDDoc As Acrobat.CAcroPDDoc Set objAcroApp = CreateObject("AcroExch.App") Set objAcroAVDoc = CreateObject("AcroExch.AVDoc") Set objAcroPDDoc = CreateObject("AcroExch.PDDoc")

最初の CreateObject を実行した時にメモリ上にAcrobatプロセスが登場します。

Acrobat ver 7、8、9,X(10)、XI(11):

'Acrobat 7,8,9,10,11 の時 Dim objAcroApp As New Acrobat.AcroApp Dim objAcroAVDoc As New Acrobat.AcroAVDoc Dim objAcroPDDoc As New Acrobat.AcroPDDoc

Newの有無は関係なく、上記の時にメモリには登場しません。上記のAcrobat OLE変数のメソッド(命令)を最初に使った時にメモリ上にAcrobatプロセスが登場します。

上記のように「・・As Acrobat.AcroXxxx」の宣言を使用していると、以下のようにVBAプログラミング中にピリオドの後で「入力候補」が表示されます。生産性も上がるし、エラーも減らせます。

Acrobat OLE変数の後にピリオドを入れると入力候補が表示される。但し、参照設定がされている時のみ。

ネット上のサンプルに以下のような「As Object」宣言をよく見かけます。

Dim objAcroApp As Object
Dim objAcroAVDoc As Object
Set objAcroApp = CreateObject("AcroExch.App")
Set objAcroAVDoc = CreateObject("AcroExch.AVDoc")

  

「・・As Object」は「入力候補」の表示機能が使えません。デバッグやメンテナンスにも手間が掛かり、またエラーの特定にも手間取ります。「・・As Object」は参照設定が不要ですがデメリットの方が多いです。

Acrobat OLE変数の宣言場所

以下の①位置のモジュールレベルでの宣言は非推奨です。②位置のSub内や③位置のFunction内での宣言使用はOKです。①位置はデバッグ時に途中で処理が中断した場合などに処理続行不能になった経験が何度も有ったからです。

VBAではAcrobat OLE変数の宣言場所に注意が必要です。

①位置が絶対に駄目という訳ではないです。エラーを出さない様な処理をする、又はデバッグをすれば正常終了します。

Acrobat OLE変数の宣言は一箇所のみ

1つ前の「Acrobat OLE変数の宣言場所」では3箇所の宣言場所を紹介しています。実際は1箇所の同じ場所に全てを宣言して下さい。複数のSubやFunction 等で散らばって宣言すると後処理とエラー処理が複雑になり大変です。

Acrobat OLE変数の宣言は一箇所のみ。複数はエラーのもと。

Acrobat OLE変数を扱う処理も全てその箇所で行います。

Acrobat OLEの終了

エラーを意識したサンプルの198~207行目の処理です。この部分に関しては「Acrobat OLEの終了(簡単に出来ない)」に詳しく書いてます。

VBAでAcrobat OLEの終了処理を行う

VBAのランタイムエラー、Acrobat OLEエラーなどの処理続行が不可能なエラーが発生しても最後に上記を実行しておけばメモリ上にAcrobatプロセスを残す事が減ります。

Acrobat OLE変数の引数での使用

関数の引数にAcrobat OLE変数が使えます。受け側はByRefで必ず宣言する必要があります。 

Acrobat OLE変数を引数に使う例です。出来ればしない方がいい。

Function ABC(ByRef a As Acrobat.AcroApp) As Boolean
の「As Acrobat.AcroApp」部分を「As Object」にするのはやめましょう。動作しますがデバッグやメンテナンスに手間が掛かり、またエラーの特定にも手間取ります。

出来れば上記のような引数を使用して他のSubやFunctionでの処理は避けて欲しいです。「Acrobat OLE変数の宣言は一箇所のみ」で書きましたが、Acrobat OLEの処理はAcrobat OLE変数の宣言箇所で行います。他のSub、Functionで処理するとエラー時の対応が大変です。

・・大変でしたが私は使いました。(後で後悔

Acrobatプロセスのチェック

エラーを意識したサンプルの26~34行目にAcrobatプロセスの存在をチェックするロジックが有ります。この時点でAcrobatプロセスがメモリ上に残っているのは、直前の処理が何らかのエラーで異常終了したか、又は手動でAcrobatアプリケーションを起動して忘れていた場合です。

If iCheckAcrobat() > 0 Then msMsg = "Acrobatが動いています。" _ & vbCrLf & "処理を中断します。" & vbCrLf _ & vbCrLf & "この後でAcrobatの終了を試みます。" MsgBox msMsg, vbCritical, "実行の中断" 'Acrobat OLEの終了を試みる Call EndAcrobat Exit Sub End If

  

iCheckAcrobat関数(246~259行目)でプロセスチェックを行い、存在する時はEndAcrobatサブ(292~313行目)でプロセスの終了を試みます。

'********************************************* ' メモリ上のAcrobatプロセスを数える。 '********************************************* Private Function iCheckAcrobat() As Long On Error GoTo skip_iCheckAcrobat: 'VBA実行時エラー Dim items As Object Set items = CreateObject("WbemScripting.SWbemLocator") _ .ConnectServer.ExecQuery( _ "Select * From Win32_Process " & _ "Where Name = 'Acrobat.exe'") '1以上はプロセス有り、0は無し iCheckAcrobat = items.Count Exit Function skip_iCheckAcrobat: miErrorNo = Err.Number msErrorMsg = Err.Description End Function

  

Acrobatプロセスに優しい終了

EndAcrobatサブ(292~313行目)でAcrobatプロセスの終了を試みます。強制でのKillは環境に良くないので使いません。

'********************************************* ' メモリ上に残ったAcrobatプロセスを ' 正常に終了させる為だけの処理です。 '********************************************* Sub EndAcrobat() On Error Resume Next Dim objAcroApp As New Acrobat.AcroApp Dim objAcroAVDoc As New Acrobat.AcroAVDoc Dim objAFormApp As New AFORMAUTLib.AFormApp Dim objAFormFields As AFORMAUTLib.Fields objAcroApp.CloseAllDocs objAcroApp.Hide objAcroApp.Exit Set objAFormFields = Nothing Set objAcroAVDoc = Nothing Set objAFormApp = Nothing Set objAcroApp = Nothing '上記の実行後にメモリ上から消える、はず。 MsgBox "Acrobat OLEの終了を試みました。" & _ vbCrLf & "10秒後にメモリから消えたのを" & _ vbCrLf & "タスクマネージャーで確認して下さい。", _ vbSystemModal + vbInformation, "お知らせ" End Sub

  

サンプルのAcrobat OLE変数の宣言(91~94行目)と同じものを使います。そして CloseAllDocs -> Hide -> Exit -> Nothing だけをします。「もしかしたら・・?」と試したら出来ました。Windows XPでもOKかと思ったが、駄目な場合も有りました。

Acrobatプロセスの強制終了

サンプルには入れてませんが紹介します。どうしても消えない時に利用して下さい。

Option Explicit Sub Main() Call TerminateAcrobat End Sub '********************************************* ' メモリ上のAcrobatプロセスを強制終了する。 '********************************************* Private Sub TerminateAcrobat() Dim items As Object Dim item As Object Set items = CreateObject("WbemScripting.SWbemLocator") _ .ConnectServer.ExecQuery( _ "Select * From Win32_Process " & _ "Where Name = 'Acrobat.exe'") If items.Count > 0 Then For Each item In items '強制終了 item.Terminate Next End If End Sub

  

非常時のやり方で動作環境的には良くないやり方と思ってます。

Acrobatプロセスをメモリ上に強制的に乗せる+AFormAutエラー対策

エラーを意識したサンプルの98~99行目にAcrobatプロセスをメモリ上に強制的に乗せる処理を追加しています。

Acrobatプロセスをメモリ上に強制的に乗せる+AFormAutエラー対策

CloseAllDocs は前の処理でエラーで開いていたままのPDFファイルを閉じます。Hide はデバッグ中などに知らない間に後ろ(デスクトップ)で表示されたAcrobatアプリケーションが有った場合に隠す処理です。

Acrobatプロセスがメモリ上に乗るのはAcrobat OLE変数の宣言部分を実行した時では無く、最初に実行したAcrobat OLEの命令(メソッド)の時です。つまり、CloseAllDocs を実行した時です。

それ以外にAFormAutオブジェクトのエラー回避の処理もしています。127行目でAcrobat JavaScriptを実行する前処理をしています。

AFormAutの実行

上記の実行時に「429 ・・・オブジェクトを作成できません」のAFormAutオブジェクトの実行エラーが頻発します。事前に一度だけ CloseAllDocs -> Hide を実行すると、そのエラーが出ません。長期の試行錯誤で見つけました。

AFormAutのエラー対策はobjAcroApp変数の使用ならば何でもOKだと思ってます。その中で CloseAllDocs と Hide が実行時にエラーが出にくい、しかも前のエラーも消してくれる、一石二鳥と思っています。

VBAランタイムエラーの対処

実行時又はデバッグ時にこれが発生し処理が中断すると結構な確率でAcrobatプロセスがメモリ上に残ってしまいます。それを阻止する為に以下の様に「On Error GoTo skip_XXXX:」でランタイムエラーを拾い、自分で処理する事です。

ランタイムエラーのエラー番号 Err.Number とそのエラーメッセージ Err.Description を上記のタイミングでバックアップします。そうしないと呼び出し元に戻った時に内容が初期化されてしまうからです。

呼び出し元は miErrorNo 変数の内容を見れば、ランタイムエラー発生後の後処理が出来ます。面倒ですが是非入れて下さい。

Windowsの再起動

どうしてもエラーが消えない。意味不明なエラーメッセージが表示される。デバッグ時に何度も操作ミス等でエラーを出してしまった。そんな時はWindowsの再起動をして下さい。再起動でエラーが消えた経験が何度も有ります。

Windows 11+MS Excel 2021

当記事は2021年11月9日以前の記事です。動作確認のメインは「Windows XP Pro+MS Office 2003+Acrobat 7? Pro」だった様に記憶しています。現在は「Windows 11 Pro 64bit+MS Office 2021 32bit+Acrobat XI Pro」です。OSもVBA環境もAcrobatのバージョンも上がりました。以前よりはエラーが出ません。でも業務用のPCは古いOS、古いMS Officeが使われている事を考慮しておく必要があります。(※私自身のバージョンは下がりました。エラーも多発します。)

Windows XPでも動くサンプルを目指します。

備考

  • 全て経験上の内容です。メーカー公式的な部分は1つも無いです。
  • Acrobat OLE宣言の New ではメモリ上にAcrobatプロセスはロードされません。Acrobat OLEのメソッドの実行時に初めてロードされます。F8のステップ実行で確認できます。

< TOPへ >



これ以降はサイト管理者が当サイト又は当ページを維持&管理するためのメモです。見る必要も無く公開用にも書いてません。

Acrobat JavaScriptの内容。

function DumpBookmark(bm, nLevel){ //レベルを示すインデントを構築 var s=""; for (var i=0;i<nLevel;i++) s+=" "; //しおりの名前とページ番号を出力 if (i==0){ n=this.numPages-1 }else{ bm.execute(); //しおりのある場所に移動 n=this.pageNum } p+=(s+"\r\n"+("00"+i).slice(-2)+","+ ("0000"+(n+1)).slice(-4)+"+-"+ bm.name); //しおりの子を繰り返し出力 if (bm.children!=null) for (var i=0;i<bm.children.length;i++) DumpBookmark(bm.children[i],nLevel+1); } //しおりツリーを出力 var p=""; DumpBookmark(this.bookmarkRoot,0); event.value = p;

  

  1. 最後の「event.value = p;」は抽出した情報(テキスト)をVBA側に戻り値として渡すための命令。event.value の内容がVBA側で受け取れる。
  2. 「("00"+i).slice(-2)」はVBAのFormat文と似た機能を提供する。
  3. 「bm.execute();」を先に実行しておかないとしおりを抽出した頁番号が取得できない。「this.pageNum」が頁番号。
  4. 「this.pageNum」の頁番号は1ページ目が0。
  5. デバッグはAcrobatのJavascriptデバッガーを立ち上げて「event.value = p;」を「console.println(p);」にテストした。
    スクリプト全体を選択状態にしてエンター・キーを押すと実行する。結果は同じ場所に「console.println(p);」で表示される。
  6. 自分で自分を呼び出す再帰処理・・・。(苦手

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA



SAMURAI Plugin

コメントをする時は出来れば以下もお願いします。

  • OS名 バージョン
  • Acrobat バージョン
  • ツール(Excel等) バージョン
コメントにサンプルコードを入れる時はコードを全て全角文字列にしてください。コチラで半角に戻します。それでもエラーが回避できない時はコメント下さい。個別に対処します。



お仕事で当サイトを見ている方へ
考え込んだら、ご質問下さい。
一緒に解決策を考えましょう。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください