SWTのBrowserコンポーネント拡張のコツ2

2018年5月7日

SWTのBrowserコンポーネント拡張のコツ からの続き

拡張BrowserでのHTML取得の実装例 というところを参考に、

  • ブラウザが取得したHTMLソースを横取りして、
  • いろいろgrepやら加工やらして、
  • 自動でちょちょいと操作しちゃおう

というようなコードを書いていたのですが、取得したページが普通の場合はいいんですが、
フレームで割ってあるような場合、OLEを使用してframeオブジェクトするまではいいんですが、
そこからそのフレームのinnnerHTMLがどうしても取れなくて泣きそうな今日この頃。

フレームで分割されたページのソースを取得するにはどうするか、

それは、任意のタイミングで、

browser.execute(“top.window.status=top.frames[0].document.body.innerHTML");

ステータスバーにフレームのソースを転送(JavaScript)して、

browser.addStatusTextListener( new StatusTextListener() {
public void changed(StatusTextEvent event) {
System.out.println(event.text);
}
});

ステータス変化を捕らえるリスナを自分(ブラウザクラス)に登録していただく、という方法で、ゲット。
(JavaScriptでtop.window.statusとしないと、フレームで割れたページの場合、
フレーム数だけstatusがあるようで、リスナが多重にイベントを受け取ってしまうので注意。
ただ、browserクラスはたいていスレッドでコマンド実行するので、
多重に受けとってもいいようにしておくのがベスト。)

JavaScriptで、window.status="コマンド";
とステータス表示を変更した場合、続けて、window.status=""とやってクリアしておかないと、
どうもいつまでもイベントリスナが反応してしまうようです。

たとえばこうするといいと思います。
<input type="button" onClick="windows.status=’some.commandcommand’; window.status="; " >

MSDNを見ていたら、IE8以降になると、
frameオブジェクトから直接getDocumentできるようになるようなことが書いてあったので、
とりあえずそういう時期になったらSWTももっと便利になっているでしょうから、

今はこれ(ステータスバー経由)でいいのだ

↓ブラウザクラスを単純に継承してHTMLのソースを取得するクラスを作ったので、
↓下に書いておきます。(ほとんど上のリンク先のと同じです・・・)

public class BrowserEx extends Browser {
	
	public BrowserEx(Composite parent, int style) {
		super(parent, style);
	}

	protected void checkSubclass() {
		  // kill subclass check.
		}

	public String getText() {
		OleAutomation auto=null;
		try {
			Class c = this.getClass().getSuperclass();
			Field f = c.getDeclaredField("auto");
			f.setAccessible(true);
			auto = (OleAutomation)f.get(this);
		} catch ( NoSuchFieldException nsfe) {
			nsfe.printStackTrace();
		} catch ( IllegalAccessException iae) {
				iae.printStackTrace();
		}
		
        checkWidget();
        String htmlText = null;
        // documentオブジェクト(IHTMLDocument3インタフェース)を取得する
        int[] rgdispid = auto.getIDsOfNames(new String[] {"Document"});
        Variant varResult = auto.getProperty(rgdispid[0]);
        if ((varResult != null) && (varResult.getType() != OLE.VT_EMPTY)) {
            OleAutomation htmlDocument = varResult.getAutomation();
            varResult.dispose();
            // documentElement(IHTMLElementインタフェース)を取得する
            rgdispid = htmlDocument.getIDsOfNames(new String[] {"documentElement"});
            if (rgdispid != null) {
                varResult = htmlDocument.getProperty(rgdispid[0]);
                if ((varResult != null) && (varResult.getType() != OLE.VT_EMPTY)) {
                    OleAutomation htmlElement = varResult.getAutomation();
                    varResult.dispose();
                    // outerHTMLを取得する
                    rgdispid = htmlElement.getIDsOfNames(new String[] {"outerHTML"});
                    if (rgdispid != null) {
                        varResult = htmlElement.getProperty(rgdispid[0]);
                        if ((varResult != null) && (varResult.getType() != OLE.VT_EMPTY)) {
                            htmlText = varResult.getString();
                        }
                    }
                    htmlElement.dispose();
                }
            }
            htmlDocument.dispose();
        }
        return htmlText;
    }