TOP > *
概要
Acrobat OLE+VBAプログラミング時のエラー回避方法を紹介します。大量のPDFを連続で処理する事を前提にしています。内容は多いです。
用語:
- Acrobat OLE : VBAプログラミング内で使うAcrobat OLE(IAC)の変数や命令(メソッド)の事
- Acrobatプロセス : メモリ上のAcrobatアプリケーション(Acrobat.exe)の事。Acrobat OLEを動かすとコレが立ち上がります。
- Acrobatアプリケーション : デスクトップ上に表示されるAcrobatソフトの事
目次:
- 概要 ※ココ
- エラーの種類
- 連続処理のやり方
- エラー処理を入れたサンプル
- Acrobatプロセスの監視
- Acrobat OLE変数の宣言
- Acrobat OLE変数の宣言場所
- Acrobat OLE変数の宣言は一箇所のみ
- Acrobat OLEの終了
- Acrobat OLE変数の引数での使用
- Acrobatプロセスのチェック
- Acrobatプロセスに優しい終了
- Acrobatプロセスの強制終了
- Acrobatプロセスをメモリ上に強制的に乗せる+AFormAutエラー対策
- VBAランタイムエラーの対処
- Windowsの再起動
- Windows 11+MS Excel 2021
- 備考
エラーの種類
以下のエラーを出てしまう事が有ります。
- PDFファイルを開いたままで終了してしまった。
- 原因:ロジックのミス
- 処理は全て終わったのにメモリ上からAcrobatプロセスが消えない。
- 原因1:ロジックのミス。処理途中のAcrobat OLEオブジェトが残る
- 原因2:VBAのCallByName関数でAcrobat OLEを使用した
- 原因3:PCのスペックによる。メモリからプロセスが消えるのに数秒は掛かる場合があります。サイト管理人の非力PCでは最低6秒掛かります。数千件の連続処理を行うと10秒以上も掛かる。
- 「・・オブジェクトを作成できません。」エラーメッセージが出る。
- 原因:詳細は不明。メモリ上にAcrobatプロセスの何か・・が足りないからと予測しています。
対処方法です。これ以外にエラーを減らす工夫も入れてます。
連続処理のやり方
2種類有ります。以下の2つのサンプルを見て下さい。。
サンプル1:
推奨です。処理したいPDFファイルのパスを配列で渡して、Loop_1内でループ(For ~ Next)処理します。

- メリット
- Acrobat OLE変数の定義もAcrobat OLE終了の処理も一回しか行わない。
- Sub Loop_1 内でAcrobat OLEの処理が全て含まれている。
- PCへの負荷を少ない。
- Acrobat OLEエラーが出にくい・・と思う。
- デメリット
- Loop_1のロジックが長くなる。
- Loop_1のループ内でのエラー処理が複雑になる。
サンプル2:
非推奨です。Loop_2はPDFファイルの数だけ呼ばれます。連続処理では出来れば避けて欲しいです。

- メリット
- ロジックが組みやすい。
- 他に流用しやすい。
- エラー処理がシンプル。
- デメリット
- Acrobat OLE関連の処理がPDFファイル毎に全て実行されます。
- CPUの処理量が多い。処理時間が少し長くなる。システム負荷が多くなる。つまり動作不安定になる可能性が有る。
連続で無い場合はサンプル2がお勧めです。
エラー処理を入れたサンプル
以下の3種のエラーに対処したサンプルです。
- Acrobat OLEエラー
- VBA実行時のランタイムエラー
- デバッグ時の操作エラー、及び中断等
サンプルの処理内容です。
- 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 ブック用

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プログラミング中にピリオドの後で「入力候補」が表示されます。生産性も上がるし、エラーも減らせます。
ネット上のサンプルに以下のような「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です。①位置はデバッグ時に途中で処理が中断した場合などに処理続行不能になった経験が何度も有ったからです。

①位置が絶対に駄目という訳ではないです。エラーを出さない様な処理をする、又はデバッグをすれば正常終了します。
Acrobat OLE変数の宣言は一箇所のみ
1つ前の「Acrobat OLE変数の宣言場所」では3箇所の宣言場所を紹介しています。実際は1箇所の同じ場所に全てを宣言して下さい。複数のSubやFunction 等で散らばって宣言すると後処理とエラー処理が複雑になり大変です。

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

VBAのランタイムエラー、Acrobat OLEエラーなどの処理続行が不可能なエラーが発生しても最後に上記を実行しておけばメモリ上にAcrobatプロセスを残す事が減ります。
Acrobat OLE変数の引数での使用
関数の引数にAcrobat OLE変数が使えます。受け側はByRefで必ず宣言する必要があります。

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プロセスをメモリ上に強制的に乗せる処理を追加しています。

CloseAllDocs は前の処理でエラーで開いていたままのPDFファイルを閉じます。Hide はデバッグ中などに知らない間に後ろ(デスクトップ)で表示されたAcrobatアプリケーションが有った場合に隠す処理です。
Acrobatプロセスがメモリ上に乗るのはAcrobat OLE変数の宣言部分を実行した時では無く、最初に実行したAcrobat OLEの命令(メソッド)の時です。つまり、CloseAllDocs を実行した時です。
それ以外にAFormAutオブジェクトのエラー回避の処理もしています。127行目でAcrobat JavaScriptを実行する前処理をしています。

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

