(一部編集中)

このページについて

WindowsXPのサポート終了に伴い、業務で使うパソコンがWindows7とInternetExplorer8になり、旧環境で問題なく動作していたVBScriptが新環境でまったく動かなくなった。それに関する覚書である。

結論

VBScriptでIEを操作するスクリプトは、ここにあるイベントを捕捉する仕組みを利用し、DocumentCompleteイベントなどをトリガにして目的の作業を行うように実装していた。これがなぜIE8になってから動かなくなったのか?をWebで調査したところ、セキュリティ向上のため、IEの動作仕様が変わった、というのが理由と分かってきた。なぜ動かなくなったのか、IE動作仕様変更、などは補足に譲るとして、実際に行うことは、
  • Windowsのレジストリに、整合性レベル中を意味するIEを別名として登録する
  • スクリプト中の、CreateObjectの引数に上記整合性レベル中のIEを指定するように修正する
である。ただし、イントラネットサイト限定という前提が必要と思われる。

Windowsのレジストリに、整合性レベル中を意味するIEを別名として登録する

これには、
  • スクリプトでレジストリ読み書き
  • レジストリファイルをエクスプローラ等から実行
  • レジストリエディタで手動で編集
のいずれかを実施/実現すれば良い。いずれも結果は同じであるため、どれを選択するかは想定されるユーザのレベル、あるいは、スクリプト配布側のスタンスで選ぶ。なお、上からユーザフレンドリーな順に並べたつもりであるが、ユーザ持つ権限によっては順番が変わるかもしれない。
スクリプトでレジストリ読み書き
スクリプト中の、IE起動前にレジストリに必要な記載があるかどうかの判定および、記載がいない場合にレジストリに記載を追記する処理となるよう、以下のコードを適切な箇所に追加する。ただし、Windows7からレジストリ編集のコードを実行するには、スクリプト内で管理者権限への昇格が必要である。必ず昇格させるようにしたほうが無用のエラーは防げそうだが、WSH起動後に32ビット版で再起動するコードを書き換えて、スクリプト開発者に選択させる拡張性を持たせてもいいかもしれない。
編集中)
レジストリファイルをエクスプローラ等から実行
以下のコードを適当なファイル名のテキストファイルに保存し、実行する。
Windows Registry Editor Version 5.00 

[HKEY_CLASSES_ROOT\InternetExplorer.ApplicationMedium] 

[HKEY_CLASSES_ROOT\InternetExplorer.ApplicationMedium\CLSID] 
@="{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}"
*1
レジストリエディタで手動で編集
  1. Windowsキー+R→regeditを入力しエンター
  2. HKEY_CLASSES_ROOTで右クリック→新規→キーを選択
  3. 新しく作成されたキーの名称をInternetExplorer.ApplicationMediumに変更
  4. InternetExplorer.ApplicationMediumで右クリックし→新規→キーを選択
  5. 新しく作成されたキーの名称をCLSIDに変更
  6. CLSIDをアクティブにした状態で右ペインの(規定)で右クリック→修正を選択
  7. {D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}

スクリプト中の、CreateObjectの引数に上記整合性レベル中のIEを指定するように修正する

イベント捕捉のこれまでのコード
Set IE = CreateObject("InternetExplorer.Application", "IE_")
を以下に示すような
Set IE = CreateObject("InternetExplorer.ApplicationMedium", "IE_")
に書き換える。WinXPとWin7、IE7と8等でも動くことを意図するならば、応用として、OSとIEバージョンを取得してそれに応じたコードにするのが良さそう。

補足

なぜ動かなくなったのか

スクリプトに上記変更を入れないまま実行すると、スクリプトがQuitイベントを捕捉して終了してしまうため。
'OnQuitイベント
Sub IE_OnQuit()
	objLogFile.Write 1, "Internet Explorerが閉じられました。"

	'オブジェクトの破棄
	Set objIE = Nothing

	WScript.Quit() 'スクリプトの終了
End Sub
これは、ユーザ操作によりIEがクローズされた場合にスクリプトだけが残ってしまう(スクリプトを実行するプロセスが残ってしまう)ことに対応するため、Quitイベントを捕捉した場合、スクリプトは終了するようにしていた。WinXP+IE7ではこれまで、Quitイベントを捕捉することはなかった。

IE動作仕様変更

なぜQuitイベントを捕捉するのか
これについての直接の記事はないものの、この記事と和訳されたこの記事にある、
  • IE のインスタンスがインターネット (保護モード、LowIL) とイントラネット (非保護モード、MediumIL) の間を遷移すると、Internet Explorer は遷移を新しいプロセスでハンドルする必要があります。
  • 多くのシナリオへの互換性のため、Internet Explorer は既定のタブ プロセスを整合性低のタブであるとみなしています。したがって Internet Explorer が COM オートメーションにより生成される際、タブ プロセスの既定は整合性低のタブになります。ブラウザーはページ遷移により整合性中のタブ コンテンツ プロセスが必要であると判断すると、仮想タブ切り替えが実行されます
という記載から思いつく動作の仮説は、
  1. イントラネットサイトにアクセスを開始すると、IEは仮想タブへの切り替えを行う
  2. 切り換え時、IEはそれまで起動していた整合性低のタブを一旦停止させ、整合性中のタブを起動する
  3. 一旦停止の結果、IEはQuitイベントを発報する
のではないだろうか。

動作仕様変更に対する他の手段の検討

結局のところ、上記方法に落ち着いたのだが、この記事には動作仕様変更に対して、
  • モニカーを使った構文
  • NewProcess イベント をトラップして適切に対処する
といった対処方法が提案されている。しかしながらいずれも、VBScriptを使用したイベント捕捉タイプのコードと相性が良くない、あるいは使用できないと考えている。モニカーを使った構文、
 Set IE = GetObject("new:{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}")
では、GetObjectを使用しており、CreateObjectで指定可能なイベント捕捉に重要な第2引数が存在しない。すなわち、イベント捕捉ができないのではないだろうか。また、NewProcessイベントをトラップすることも同様に、NewProcessイベントをトラップして、引数にあるブラウザオブジェクトをスクリプト内に用意した変数にSetする、までは良さそうだが、Setしたブラウザオブジェクトのイベント捕捉ができないスクリプトに戻ってしまいそうで、これも採用できない。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

管理人/副管理人のみ編集できます