
以前、上記の記事でIEオブジェクトをVBAから制御して処理させる方法を記載しましたが、これを自動実行プログラムとして運用していくとたまに次のようなメッセージで止まることがありました。
実行時エラー’-2147023706(800704a6)
オートメーションエラーです。
システムのシャットダウンは既にスケジュールされています。
これについて原因と対策を実装したので記載します。
オートメーションエラーの原因
どうやらCreateObjectで生成したIEオブジェクト1つを使いまわす分には問題ないですが、プロシージャレベルで生成→操作→終了→破棄となっているものを何度も呼び出すと2回目以降、稀にこれが起こることが分かりました。
例えば次のようなソースです。
1 2 3 4 5 6 7 |
Public Sub navIeTest() Set oIE = CreateObject("InternetExplorer.Application") oIE.Visible = True Call oIE.Navigate("http://blog.miminoinu.net") oIE.Quit Set oIE = Nothing End Sub |
これ単体では何も問題ないです。ですがこのプロシージャが何度も呼び出された場合、最後の
Set oIE = Nothing
での処理がすぐ完結しないときがあるようで、その後に実行される
Set oIE = CreateObject(“InternetExplorer.Application”)
のところでこのエラーが出るといった具合です。
解決方法としては次の方法があります。
- 案①:プログラム起動時に1度だけCreateObjectしたIEオブジェクトを上位スコープ変数として持ち、プログラム終了までずっと使いまわす
- 案②:IEを利用するときに、既にIEがいるならそれをバインドして利用する。ないなら生成する。
①の方法が良いのでしょうが、そうするとローカル関数で生成しているオブジェクト生成と破棄を実施しているソースコードに1つ1つパラメータ引数で渡してあげなければならないのもいやなので(グローバルは使わない方針w)
今回は修正方法が楽な②の方法としました。まず、次の関数を作ります
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
' IEオブジェクトを取得するなければ作成する Public Function getIE() As Object Dim objSh As Object Dim objW As Object Dim i As Integer 'IEがすでに立ち上がっている場合はそれを活用する Set objSh = CreateObject("Shell.Application") For i = objSh.Windows.Count To 1 Step -1 Set objW = objSh.Windows(i - 1) If objW.FullName Like "*iexplore.exe" Then Set getIE = objW Exit Function End If Next '見つからなかった場合は新規作成する Set getIE = CreateObject("InternetExplorer.Application") getIE.Visible = True End Function |
次にさきほどのテストソースは次のように修正します。
1 2 3 4 |
Public Sub navIeTest() Set oIE = getIE Call oIE.Navigate("http://blog.miminoinu.net") End Sub |
今度は終了時の処理です。まずこの関数を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
' IEオブジェクトをすべて終了させる Public Sub quitIE() Dim objSh As Object Dim objW As Object Dim i As Integer Set objSh = CreateObject("Shell.Application") For i = objSh.Windows.Count To 1 Step -1 Set objW = objSh.Windows(i - 1) If objW.FullName Like "*iexplore.exe" Then objW.Quit End If Next End Sub |
で、プログラムの終了時にIEオブジェクトを掃除します。
1 2 3 |
Public Sub Auto_Close() Call quitIE End Sub |
コードは前よりもシンプルになり、また変なエラーも出なったかと思います。