WScript - HTA 相互通信ライブラリ2007年06月05日 20時40分45秒

ってほど大層なもんじゃないけど、まあこれも一種のIPCになるかなぁ、と思ったり。

scripthost.jsのソース

まずはライブラリコードから。これはwsh・htaの両方から共通で使用する。要:prototype.js

Object.extend( Enumerator.prototype, {
	_each : function(iterator) {
		this.moveFirst();
		var i = 0;
		try {
			for(; ! this.atEnd(); this.moveNext()) {
				try {
					iterator( this.item(), i++ );
				} catch(e) {
					if( e != $continue ) throw e;
				}
			}
		} catch(e) {
			if( e != $break ) throw e;
		}
	}
} );
Object.extend( Enumerator.prototype, Enumerable );

var WshHost = Class.create();
WshHost.prototype = {
	initialize : function(hWnd) {
		if( isNaN( hWnd ) ) {
			this._ie = new ActiveXObject("InternetExplorer.Application");
		} else {
			this._ie = new Enumerator( new ActiveXObject("Shell.Application").Windows() ).find( function(ie) {
				return ie.hWnd == hWnd;
			} );
			if( ! this._ie ) throw new Error( "ie not found" );
		}
		this.id = this._ie.hWnd;
	},
	setHost : function(host) {
		this._ie.PutProperty( "Host", host );
	},
	getHost : function() {
		return this._ie.GetProperty( "Host" );
	}
}

使い方

コンストラクタは役割によって使い分ける。先に起動しているほうは引数なしで実行、後で呼び出された側では、コマンドライン引数かなにかでIEのhWndを受け取って、それを引数として実行する。

次にホストオブジェクトを設定するほう(=wsh側だな)がsetHostメソッドを実行する。引数はHTA側に渡したいオブジェクトならなんでもよいが、「HTAからWScriptのグローバルコードへアクセスする」のであればグローバルな「this」を渡す。

受け取り側(HTA側)ではgetHostメソッドでホストオブジェクトを受け取る。

後は工夫次第でお互いに通信が可能になる。

サンプルコード(HTA)

WSHからダイアログ扱いされるHTAのサンプルを以下に示す。ファイル名は「test.hta」とする。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>test</title>
<script src="prototype.js"></script>
<script src="scripthost.js"></script>
<script>
window.resizeTo( 450, 120 );
</script>
<hta:application id="hta"></hta>
<script>
// trimメソッド追加
String.prototype.trim = function() {
	return this.replace( /^\s*/, "" ).replace( /\s$$/, "" );
}

// コマンドライン引数
this.Arguments = (function(src) {
	var result = [];
	var buf = {
		_buf : [],
		mode : false,
		push : function(c) {
			this._buf.push( c );
			if( /["']/.test( c ) ) {
				if( ! this.mode ) {
					this.mode = true;
				} else {
					this.value = this._buf.slice(1, this._buf.length - 1).join("");
					this.mode = false;
					this._buf = [];
					return false;
				}
			}
			return true;
		},
		finish : function() {
			if( this._buf.length == 0 ) return null;
			return this._buf.join("");
		}
	};
	for(var i = 0; i < src.length; i++) {
		if( ! buf.push( src.charAt(i) ) ) {
			result.push( buf.value );
		}
	}
	result.push( buf.finish() );
	return result.compact();
})( hta.commandLine.trim() );
</script>
<style>
</style>
<body>
<input type="file" id="file1" size="60">
<button id="btn1" disabled>確定</button>
</body>
<script>
// test.jsから渡されたhWndを引数にWshHostを初期化
var wshHost = new WshHost( this.Arguments[1] );
// ホストオブジェクト(=test.js内の'this')を取得
var host = wshHost.getHost();

Event.observe( $("file1"), "change", function() {
	$("btn1").disabled = false;
}, false );

Event.observe( $("btn1"), "click", function() {
	// test.jsのfileNameにパスをセット
	host.fileName = $("file1").value;
	// test.jsに終了を通知
	host.quit = true;
	// HTA自体も終了
	window.close();
}, false );
</script>
</html>
コマンドライン引数の解析のコードがちょっとうざいが我慢して欲しい。

コードはそれほど複雑ではなく、input type=fileでファイルを選択して「確定」をクリックすると、呼び出し元のWSHにファイルパスと終了を通知して終了する。

サンプルコード(JS)

ちょっと長いので、ライブラリロードだの、echoだのreadlnだのの定義は省略し、肝心の部分のみ記載する。ロードするライブラリは「dummy.js」、「prototype.js」および今回の「scripthost.js」の3つ。dummy.jsはここらあたりのものを拾って使って欲しい。

ファイル名はこちらも単純に「test.js」としておこう。

var shell = new ActiveXObject("WScript.Shell");

var wshHost = new WshHost();
wshHost.setHost( this );

// HTAの終了待ち合わせフラグ
var quit = false;
// HTAで選択したファイルパスを受け取る変数
var fileName = null;

echo( "ファイルを選択してください。" );
shell.Run( [ "test.hta ", wshHost.id ].join("") );
while( ! quit ) {
	WSH.Sleep( 100 );
}

echo( "選択されたファイル:", fileName );

で、実行すると

  1. test.jsを起動すると自動的にtest.htaが呼び出される
  2. test.htaでファイルを選択し、「確定」をクリックするとtest.htaは終了
  3. test.jsのコンソールにはhtaで選択したファイルのパスが表示される
と、たったこれだけ。だが、この方法ならcscriptから呼び出し可能なカスタムダイアログが作れると思う。IEにHTAのwindowをセットするとかできそうだし。

サンプル一式

今回のサンプルコード一式を以下のリンクからダウンロードできるようにした。

prototype.jsも1.5.1を同梱している。prototype.js以外のjs、htaはnyslとする。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2007/06/05/1557911/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。