WSHでMSHTML.HTMLDocumentを扱えた2007年10月14日 05時41分08秒

久々のWSHネタ

via: Windows Script Programming: コマンドラインでHTMLファイルをテキストファイルにする。

うは、こりゃすごい。昔2chのWSHスレで「InternetExplorer.ApplicationをcreateしなくてもMSHTML扱える」っていうようなレスを見たことあったんだけど、具体的にどうやるのか知らなかったが、リンク先の記事にばっちり書いてあった。

こんな方法で取得できるとは...

この記事では、

var htmlfile = new ActiveXObject("htmlfile");
ってな方法でオブジェクトを作成していて、これでMSHTMLのHTMLDocument(=documentオブジェクト)が取得できる。

んで、これのparentWindowを参照するとHTMLWindow2(=windowオブジェクト)があっさり取得できる(ちなみにこのwindowのlocation.hrefはabout:blankだった)。

ちなみにこの操作を行ってもIEのプロセスは起動していなかった。インプロセスでIE相当のオブジェクトを取得できたわけだ。

クリップボード使い放題

WSHでクリップボードを扱う場合はIE経由が定番だったのだが、IEはアウトプロセスサーバのため、インスタンスの生成コストがべらぼーに高く、あんまり手軽に扱えなかった。

が、今回の方法は前述のとおりインプロセス動作のようなので、さくっとwindowオブジェクトにアクセスでき(IE経由の場合と違い、わざわざabout:blankにnavigateしなくてもいいし)、

var ClipUtil = {
	get : function() {
		return new ActiveXObject("htmlfile").parentWindow
			.clipboardData.getData("text");
	},
	set : function(text) {
		new ActiveXObject("htmlfile").parentWindow
			.clipboardData.setData("text", text);
	}
};
なんてユーティリティ作って、さくさくとクリップボードデータが操作できたりする。また、インプロセスだから終わった後にプロセス落とさなくてもいいってのもうれしい。

IEのコンテキストメニュー拡張2007年05月09日 20時15分34秒

なんとなく試してみたくなったり

普段GreatNewsというRSSリーダーを使っている。動作は軽快だしあまり不満はないのだが、内蔵のタブブラウザの機能がおまけ程度の機能しかないのでちょっと不満に思っていた。

んで、いままではリンクURLをコピーしてFirefoxに貼り付けていたのだが、読みたい記事がたまってくるとそれも面倒になってきた。要するに「Firefoxで開く」というメニューが欲しくなったのだ。

たぶんその手の右クリック拡張あるだろうなーと思って探していたら「そんなん、自分で作れ。」とばかりにR-Click! Union 拡張メニュースクリプトの作り方が見つかったので自作することに。

簡単じゃん、と思ったら

具体的な方法は先のリンク先を見てもらえばわかるので割愛するが、あとはメニューから呼び出されたときに

  • 右クリックされたリンクを取得し、
  • WScript.Shell.Run( url )で蹴っ飛ばせば
  • 標準のブラウザで開けるので以下のようなhtmlを書いてみた。withブロックで囲ってるのは単に好みの問題なのでご容赦を。
    <-- もう消しちゃったスクリプトだから動くかわかんないや。 たぶん平気だけど。-->
    <script language="JScript">
    with( external.menuArguments ) {
    	new ActiveXObject("WScript.Shell").Run( event.srcElement.href );
    }
    </script>
    
    メニューはリンク上での右クリック時のみに設定してあるため、このように非常にシンプルだ。(実はそうでもなかったが)

    ところが考えてみれば当たり前で、このスクリプトではセキュリティ警告がでてしまう。はて。

    工エェ(ry、VBSならいいの??

    他にレジストリ登録されている拡張メニューを見たところ、昔インストールした「紙 2001」(紙copiの前身)の取り込みメニューが登録されており、そちらを参考にさせてもらったところVBScriptでCreateObjectしていた。

    半信半疑で先のスクリプトをVBSで書き直そうと思ったが、ずいぶんとVBS書いてなかったのと、ものすげー冗長になるのが目に見えていたのでWScript.Shellを取得する部分のみおそるおそるVBSに置き換えた次のようなスクリプトを書いてみた。

    <-- もう消しちゃったスクリプトだから動くかわかんないや。 たぶん平気だけど。-->
    <scritp language="VBScript">
    Function GetShellObject()
    	Set GetShellObject = CreateObject("WScript.Shell")
    End Function
    </script>
    <script language="JScript">
    with( external.menuArguments ) {
    	GetShellObject().Run( event.srcElement.href );
    }
    </script>
    
    うまくいくじゃん!!...なんだか納得いかんけど。

    ひょんなことから

    まあ不恰好だがよいか、と思ってちょろちょろとテストしていたら、imgなリンクの時にはメニューが表示されないことに気がついた。場当たり的にレジストリのcontextsの値に画像時のフラグも加えたが、今度はevent.srcElementがimgになるので当然リンク先が取得できない。ああ、探索する必要があるのね、ふぅ。

    で、再帰で要素をバブリング探索するように書き換えてついでになにを思ったか未練たらしくVBS廃止→new ActiveXの復活をして以下のようなコードにした。

    <script language="JavaScript">
    with( external.menuArguments ) {
    	( function(ele) {
    		if( /^a$/i.test( ele.tagName ) ) {
    			new ActiveXObject("WScript.Shell").Run( ele.href );
    		} else {
    			if( ele.parentElement )
    				arguments.callee( ele.parentElement );
    		}
    	} )( event.srcElement )
    }
    </script>
    
    なぜか警告がでなくなった。はれ?

    それでいいのか?俺が悪いのか?

    警告でないじゃん、と思ったのはつかの間、これimgなリンクだと大丈夫で、普通のリンクだと怒られるという不可思議な現象になっていた。え、ひょっとしてコールスタックの数で挙動に違いが?本当か??

    またもや疑問をいだきつつ、コールスタックを稼ぐためにnew ActiveXObjectのみ別関数にしたところ、普通のリンクでも警告が出なくなった。

    <script language="JavaScript">
    function getShell() {
    	return new ActiveXObject("WScript.Shell");
    }
    
    with( external.menuArguments ) {
    	( function(ele) {
    		if( /^a$/i.test( ele.tagName ) ) {
    			getShell().Run( ele.href );
    		} else {
    			if( ele.parentElement )
    				arguments.callee( ele.parentElement );
    		}
    	} )( event.srcElement )
    }
    </script>
    
    本当にそれでいいのか?

    まぁ、ともあれ。

    セキュリティホールっぽく感じたのでスタック数を指定してWScript.Shellをnewするスクリプトを貼り付けたHTMLをIEに読み込ませたところ、スタック量に関係なくセキュリティ警告が表示された。あ~、びっくりした。

    ともあれ、これでGreatNews環境がすこしだけ快適になったのでよしとしよう。