スポンサーリンク

Java のスクラップブックを HTML + JScript で作る (HTAで子プロセスを操作)

スクラップブックとは,Javaのソースコードの「断片」を,その場ですぐ実行できるというツール。

Eclipseに付属しており,ちょっとしたメソッドの動作確認をしたい時に重宝する。

ちょっと動かすだけじゃない、eclipseスクラップブックページのとても便利な使い方
http://symple.jp/10.html

コンパイル言語なのに,まるでスクリプト言語のように使える。



これの簡易版を HTMLJScript(HTAアプリケーション)で作ってみる。

関連するTipsは

  • JScript で,子プロセスを起動して標準出力を得る方法
  • JScript で,特定の時間だけスリープする方法

など。


下記ソースコード:


適当な名前.hta で保存。ダブルクリックでGUIが開く。

<html>
<head><title>java scrap</title></head>
<body bgcolor="#eeeeff">

<center>

<h4>javaコード</h4>

<textarea cols=100 rows=9 id="txtCode">System.out.println( "Hello,World!" );
//System.out.println( System.getProperties() );
</textarea>

<br><br>

<input type="button" onClick="exec()" value="   実行   ">

 

<input type="checkbox" id="cbxDelClass" checked=true> 実行後 .class を消去
 
<input type="checkbox" id="cbxDelSrc"> 実行後 .java を消去

<br><br>

<h4>出力</h4>

<textarea cols=100 rows=9 id="txtOutput"></textarea>

<br><br>

<input type="button" onClick="txtOutput.value=''" value="   クリア   ">

</center>

<script language="JavaScript">

function exec()
{
	// 定数
	var ForReading   = 1; // 読み込み
	var ForWriting   = 2; // 書き込み(上書き)
	var ForAppending = 8; // 書き込み(追記)


	// javaファイル作成


	// 新規テキスト
	var class_name = "TempScrap";
	var file_to = class_name + ".java";
	var file_class = class_name + ".class";
	var fso_w = new ActiveXObject( "Scripting.FileSystemObject" );
	if( fso_w.FileExists( file_to ) )
	{
		fso_w.DeleteFile( file_to );
	}
	fso_w.CreateTextFile( file_to );
	var txt_w = fso_w.OpenTextFile( file_to,   ForWriting );

	// ソースコード
	var strsrc = "class TempScrap {\r\n"
		+ "  public static void main ( String args[] ) {\r\n"
		+ txtCode.value + "\r\n"
		+ "  }\r\n"
		+ "}"
		;
	txt_w.WriteLine( strsrc );
	txt_w.Close();


	// コンパイル


	var excel = new ActiveXObject("Excel.Application");
	var cmd_cl = "cmd.exe /c javac " + file_to;
	var ws = new ActiveXObject( "WScript.Shell" );
	// 実行
	var ws_cl = ws.Exec( cmd_cl );
	while( ws_cl.Status == 0 )
	{
		// ウェイト
		excel.ExecuteExcel4Macro( "CALL(\"Kernel32\",\"Sleep\",\"JJ\",1000)" );
	}
	var res_cl = ws_cl.StdOut.ReadAll();

	// コンパイル成功か調べる
	if( ! fso_w.FileExists( file_class ) )
	{
		txtOutput.value += "【コンパイル失敗】\n";
		return;
	}


	// 実行


	var cmd_exec = "cmd.exe /c java " + class_name;
	var ws_exec = ws.Exec( cmd_exec );
	while( ws_exec.Status == 0 )
	{
		excel.ExecuteExcel4Macro( "CALL(\"Kernel32\",\"Sleep\",\"JJ\",1000)" );
	}
	var res_exec = ws_exec.StdOut.ReadAll();
	// 標準出力を取得
	txtOutput.value += res_exec;


	// 後処理
	if( cbxDelClass.checked )
	{
		fso_w.DeleteFile( file_class );
	}
	if( cbxDelSrc.checked )
	{
		fso_w.DeleteFile( file_to );
	}

	return;
}

// ※古いclassファイルが残ったままだと,コンパイルエラー時には古いclassが実行されます。

</script>

</body>
</html>


実行画像:



上のボックスにコードを書き,実行ボタンを押下すると,下のボックスに実行結果が出る。


コードの注意点を幾つか:

(1)最初から WScript オブジェクトが無い

HTAなので,ブラウザ上でJScriptを動かしているような状況であり,WSHとは異なる。

var fso_w = WScript.CreateObject( "Scripting.FileSystemObject" );

のかわりに

var fso_w = new ActiveXObject( "Scripting.FileSystemObject" );

とする。

WScript.Echo() でのアラートも不可だから,通常のJavaScriptと同じで alert() を使ってよい。

(2)子プロセスの出力結果を得る際,待つ

WScript.ShellでExecをかければ,外部コマンドを実行できる。


この際,Statusプロパティを監視して,ジョブが実行中かどうかを判定する。

ジョブが終了した時点で完全な標準出力を取得できる。

MS-DOSコマンドの標準出力を取得する
http://officetanaka.net/excel/vba/tip...

Status プロパティ (WshScriptExec)
http://msdn.microsoft.com/ja-jp/libra...

  • WshRunning ( = 0) ジョブはまだ実行中です。
  • WshFinished ( = 1) ジョブの実行が完了しました。

(3)Sleepメソッドが無い

(2)より,ジョブが終了したかどうか待つ必要があるわけだが,(1)の通り WScript が無いので,WScript.Sleep() が使えない。

かわりに,Excelマクロを呼び出すことによってウェイトを実現できる。

excel.ExecuteExcel4Macro( "CALL(\"Kernel32\",\"Sleep\",\"JJ\",1000)" );

これで1000ミリ秒ポーズできる。


setInterval(+mshta)を使ってタイマー処理する方法もある。

HTAを使ってウェイトをかける
http://maglog.jp/pueblo-del-script/in...

基本的なファイル処理については,下記記事中のコードを参照。

バッチで文字列を置換する (JScriptでテキストファイル処理)
http://language-and-engineering.hatenablog.jp/entry/20081017/1224168811


日経平均株価の下落ぶりをMIDIサウンドで味わう (コマンドラインでMIDI生成)
http://language-and-engineering.hatenablog.jp/entry/20081027/1225038111

補足:import文について

Eclipseの本家スクラップブック機能の使い方と同じだが,スクラップコード中にimport文は書けないので,クラスは完全修飾名を使うこと。

java.util.HashMap<Integer,String> map = new java.util.HashMap<Integer,String>();
map.put(99,"a");
map.put(-1,"b");

System.out.println( map.get(99) );

java.util.の部分を省略してはいけない。
これでEclipse下部のコンソールに a と表示される。