読者です 読者をやめる 読者になる 読者になる

日々是雑記。

日記、文房具、気になっている端末、ゲーム、少しだけVBAなどプログラム。

VBAから目的のIEウィンドウを操作してみる -ウィンドウ特定編-


新年明けましたね。
こんにちは、蒼です。
今年も忘れた頃にやってきますので、見かけた際にはどうぞよろしくお願いします。


さて、たまには備忘録的な意味も込めて、プログラムのことでも語ろうかなぁとか思います。


ド底辺ではありますが、ワタクシも企業常駐開発エンジニアの端くれ。
プロパーさん(常駐先企業の社員さん)の作業効率化のために様々なツールを作成するんですよ。
そこそこ余裕な顔して優雅に褒められる毎日の、水面下では白鳥ばりに必死です。要求が目に見えて高くなるんだもの。

テスター上がりの底辺PGですからね。手軽なExcelVBAで何事も解決するわけですよ、力づくで
社内ポータルをお持ちの現場だとわかると思いますが、ExcelからIEを操作する機会の多いこと多いこと。
今となっては日常ですので何をいうこともありませんが、最初は難易度にドン引きしたものです。

とはいえ今でも面倒であるという点は否定しませんが……。

IEのバージョンがどうのこうのとかIFRAMEを使っているページとFRAMEを使っているページと平打ちのページが混在しているとか、歴史の古い企業だと諸々あるんです。
Wait処理だってBusyとReadyStateでの単純な処理じゃ、動いたり動かなかったりして血の涙ですよ。

ちゃんとツールが動いたら、やっぱり楽しいんですけどね。
まぁそれはそれとしまして。


操作対象のウィンドウを特定する(前段)


これなんですよ。

イマドキの情報化社会ですのでExcelだけで完結する仕事は滅多にありません。
「人間のミスをなくすには極力自動化」がトレンドです。
そこで今日の話題ですね。

すでに開いているウィンドウから情報を云々する際、先日まで下記のステップで操作対象のウィンドウを特定していました。


1. ObjectにShell.Applicationを設定
2. ウィンドウを順番に確認
3. アプリケーションのフルパスにiexplorer.exeが含まれていたらタイトルを取得
4. 目的のタイトルと比較、一致していれば操作対象のウィンドウとする


Dim Sh As Object
Dim Pg As Object  
Dim IE As Object
Set Sh = CreateObject("Shell.Application")  
'ウィンドウを順番にチェックする

For each Pg In Sh.Windows

    'IEであるか確認する
    if Instr(Pg.FullName, "*.iexplore.exe")>0 Then

        'ウィンドウのタイトルを確認する
        if Instr(Pg.document.title,目的のタイトル) >0 Then

            Set IE = Pg
            Exit For

        End if
    End if
Next Pg

'必要に応じてIEを戻り値とする



社内の限られた環境、そしてIE限定だからこそできるという、なんて乱暴かつ簡単な方法であることか!

しかしこれ、一般的に公開しようとするとIEのバージョンやらOfficeのバージョンやらで一気にややこしくなるんですよねぇ。
同じ社内環境ですら、よくわからないエラーが発生したりもしますし。(エンジニアにあるまじき発言)

こんな辺境にまでいらっしゃる程こまめなVBA紳士淑女の皆さまはご承知の通り、Shellで扱う対象にはエクスプローラーも含まれます。おけおけ。IEのチェックも入れましょう。

が。

if Instr(Pg.FullName, "*.iexplore.exe")>0 Then←エラー発生(not常時yes時々)
if Instr(Pg.document.title,目的のタイトル) >0 Then

なぜそこでエラー……。しかもテスターの人の端末・アカウント限定で……。

IEであるかのチェックも入れているというのに、それすら何かの理由ですり抜けることがあったりします。なにそれ。
同じフロアでのエラーならまだしも、別部屋、別拠点でプログラムを使っていたりしたらもう、盛大な爆死の未来しか見えません。
「テスターの環境特有」なんて踏ん反り返っていれば足元をすくわれる事でしょう。


操作対象のウィンドウを特定する(本題)



エラーが出るなら最初からエラーなど踏み潰してしまえばいいじゃない。

乱暴な私はさらに乱暴な方針を打ち立てました。
ステップ的にはこんな感じです。


1. ObjectにShell.Applicationを設定
2. ウィンドウを順番に確認
3. エラーによる中断を無視←New
4. フルパス確認なんてしゃらくせぇ!とばかりにいきなりウィンドウタイトルを取得←New
5. さすがにエラー無視を解除←New
6. 取得したタイトルと目的のタイトルを比較、一致していた場合は目的のウィンドウであると判断


Dim Sh As Object
Dim Pg As Object
Dim IE As Object 
Dim IeTitl As String

Set Sh = CreateObject("Shell.Application")

For each Pg In Sh.Windows
    'まずは変数を空文字列で初期化
    IeTitl = ""

    'ここから力任せのエラー無視
    On Error Resume Next
    
    '無理やりタイトル取得
    IeTitl = Pg.document.title

    'エラー無視を解除
    On Error Goto 0

    'タイトルの比較
    If Instr(IeTitl,目的のタイトル)>0 Then

'以降は前段のコードと同一



はい乱暴乱暴。
でも、タイトルが設定されているページを相手にするなら汎用性ありすぎじゃないでしょうか。
万が一IEのexeファイルが違う名前であっても、IEIEであれば動くコード!素晴らしい!
これならIEのウィンドウがないとかエクスプローラーのタイトルまで探しに行っちゃった☆とかいうウッカリミスも防げますね!


おわりに


自画自賛したコードですが、残念な点もいくつかあります。


* そもそもIEだけを対象にしている(他のブラウザでは未検証)
* 何か致命的なミスを見落としている


なにぶん社内で利用する目的で作ったプログラムですので、IE8とExcel2010(32bit)という狭すぎる範囲を対象にしています。
だから他のブラウザでも動くかは全くの未検証。ブラウザの判定、Officeのバージョンチェックすら入れてません。

それも大きな難点ですが、なによりも致命的なミスが含まれていないかどうか……。

紳士淑女の皆様、他人のコードを使うときは自己責任ですぞ!


01.05/2017