最強のHTAを求めて。

HTAのこれまでと現状については面倒なので略すが、現状HTAはまだ動くには動くが、デフォルトのままではIE7相当の機能でしか動かず、X-UA-Compatibleの指定でIE10以上に設定すると、HTA固有のHTA:APPLICATIONタグの機能が大きくスペックダウンし、起動パラメータが参照できなくなったり、外観や挙動の制御が制限されたりとかになってしまう。

それを回避するために、起動用のHTAを使って、旧バージョンでのフルスペックの機能設定を行った上で、本命のHTAにリダイレクトする、という方法が編み出された。

>IE10モード以上のHTAでHTA:APPLICATIONオプションを使う方法 | while(isプログラマ)
>https://am-yu.net/2015/04/26/ie10-ie11-htaapplication/

これは大変すばらしい技だが、構成が２つHTAに分かれてしまう、という欠点がある。そこで１つのHTAでこれを実現できないものか？とあれこれ考えて、とりあえず動くものが出来たのでメモ代わりにここに残す。

基本的な考え方は以下の通り。

・バッチファイルにWSH/JScriptとHTAを埋め込む。
・JScriptで起動用のHTAをテンポラリに生成し、元のHTAのHTA:APPLICATIONタグをコピーする。
・起動用HTAから元のHTAをリダイレクト表示してテンポラリファイルを削除する。

そのためのポイントは以下の通り。

・基本的な考えは前述の「IE10モード以上のHTAでHTA:APPLICATIONオプションを使う方法」。
・Chakraエンジンでは<!--がコメント扱いになることを利用して、バッチファイルとして記述したHTAに、自身をChakraエンジン用JScriptとして起動するバッチコマンドをHTAのコメントとして記述する。（上部）
・さらに同様にHTAのコメントとして起動用HTAの生成と実行を行うChakraエンジン用JScriptを記述する。（下部。HTA部分を/* */ でコメントアウトする都合上、下部に */ の追加が必要なので、ついでにコード部分を下に置いた。）

今回はそこまでやってないが、WSH/JScriptからHTAを起動するので、コマンドラインパラメータをオブジェクトにしてJSON化＆encodeURIComponentしてgetパラメータで渡せば、コマンドライン・パラメータをHTAに引き渡せる。HTA:APPLICATIONのcommandLineプロパティを解析して取得するよりは全然楽なはず。

で、これがコード。バッチとして起動するのと、MSHTAコマンドから起動するのとでの微妙な違いをご覧いただきたい。 

``` SampleHTA.bat
<!-- : ^
/*
@cscript //nologo //E:{1b7cd997-e5ff-4932-a7a6-2a9e636da385} "%~f0" %*
@exit /B
:↑でバッチ自体は終了するので、ここからはバッチからは無視される。
:↓ここに HTA コードを記述する (／＊～＊／のコメントは使えないので注意  */
/* /////////////////////////////////////////////////////////////////// -->

<!DOCTYPE html>
<html lang="ja">
<!--
サンプルダミーHTA --- ボタンを押しても何も起きません。
-->
<head>
    <meta http-equiv="content-type" content="text/html; charset=Shift_JIS">
    <meta http-equiv="content-script-type" content="text/javascript">
    <meta http-equiv="content-style-type" content="text/css">
    <meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
    <title>input box</title>
    <hta:application id="oHTA" 
        applicationname="input box" 
        border="thick"
        caption="yes"
        maximizebutton = "no"
        minimizebutton = "no"
        selection = "no"
        showintaskbar="yes"
        singleinstance="yes"
        sysmenu="yes"
        windowstate="nomal">
    <style type="text/css">
        * { margin: 0; padding: 0; }
    </style>
    <link rel="stylesheet" type="text/css"
        href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/ui-lightness/jquery-ui.css" />
    <script type="text/javascript"
        src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
    <script type="text/javascript"
        src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js"></script>
</head>
<body onresize="window.resizeTo(432,188);" onLoad="window.resizeTo(432,188);" style="background-color: whitesmoke;" >
<div style="position: absolute; left: 3mm; top: 3mm; font-size: 10pt;">
入力してください。
</div>
<input id="text1" type="text" name="text1" size="68" style="position: absolute; left: 3mm; bottom: 3mm; font-size: 10pt; height: 1.5em; ">
<button id="btnOK" type="button" name="btnOK" style="position: absolute; right: 3mm; top: 3mm; font-size: 10pt; height: 2em; width: 7em">OK</button>
<button id="btnCAN" type="button" name="btnCAN" style="position: absolute; right: 3mm; top: 13mm; font-size: 10pt; height: 2em; width: 7em">キャンセル</button>
<script type="text/javascript">
//
</script>
</body>
</html>

<!-- */ /////////////////////////////////////////////////////////////////
// ↑ HTA コードここまで。以下は起動用コード

genHTAkicker( WScript.ScriptFullName )();

// HTA 再起動
function genHTAkicker( file ) {
    var fso = typeof(fso)==='undefined' ? WScript.CreateObject('Scripting.FileSystemObject') : fso;
    var mch, str, xuae, ie=7, app, hta;
    file = fso.GetAbsolutePathName( file );
//  str = _.file2text( file );
    var f = fso.OpenTextFile( file, 1 );    //  iomode 1:ForReading
    if( ! f.AtEndOfStream ) str = f.ReadAll();
    f.close();

    // 雑な正規表現(1) X-UA-Compatible 定義の抽出
    if( mch = str.match(/\<.*"X\x2DUA-Compatible".*\>/) ) {
        xuae = mch[0];
        if( mch = xuae.match(/"IE=([^"]+)"/) ) ie = mch[1];
    }
    // 雑な正規表現(2) HTA:APPLICATION 定義の抽出
    if( mch = str.match(/\<HTA\x3AAPPLICATION[\S\s]*?\>/im) ) app = mch[0];
    
    if( parseInt(ie) <=9 ) return void 0;
    
    hta = "\
<!DOCTYPE html>\n\
<html>\n\
<head>\n\
    <meta http-equiv='X-UA-Compatible' content='IE=9' />\n\
    <meta http-equiv='refresh' content='0;URL=" + file + "?kicked'>\n\
    " + app + "\n\
</head>\n\
<body>\n\
    <script>\n\
        var fso = new ActiveXObject('Scripting.FileSystemObject');\n\
        window.addEventListener('unload', function(event) {\n\
            fso.DeleteFile('@@@@@@@@');\n\
        });\n\
    <\x2Fscript>\n\
</body>\n\
</html>";
    
    // kicker生成
    return function kickHTA(){
        var fso = typeof(fso)==='undefined' ? WScript.CreateObject('Scripting.FileSystemObject') : fso;
        var WshShell = typeof(WshShell)==='undefined' ? WScript.CreateObject('WScript.Shell') : fso;
//      var tempfile = _.genTempPathEasy();
        var tempfile = ( ((new Date()).toLocaleString()).replace( /([^\d])(\d)(?=[月日:]|$)/g, "$10$2" ) ).replace( /[^\d]+/g, "" );
        tempfile = fso.BuildPath( fso.GetSpecialFolder(2), tempfile );
        hta = hta.replace( /@@@@@@@@/, tempfile.replace(/\\/g,"/") );
//      _.text2file( hta, tempfile );
        var f = fso.CreateTextFile( tempfile, true );
        f.Write(hta);
        f.close();
//      WshShell.Run( 'MSHTA ' + tempfile + ' & del ' + tempfile, 1, true );
        WshShell.Run( 'MSHTA ' + tempfile, 1 );
    }
}

// この行は消さないこと。 -->
```

作るには作った。が、大袈裟すぎる。微妙な違いのためにこれかよ。どうしても１ファイルにしたいとき以外は２ファイル構成にする方がお手軽だし、IE10以降固有の機能まで必要ないなら、IE=9を指定してやればES5で使えるし、commandLineプロパティも含めHTA:APPLICATIONの機能がフルセットで動くので、それでいいじゃないのよ。というのが結論である。やれやれ。