イネマルのプログラミング備忘録

趣味プログラマのメモ

WSH wsf の resource を外部ファイルに切り出す(WSC を使った実装の分割)

はじめに

WSH(.wsf) では、<resource>タグを使って任意のテキストデータをスクリプトに埋め込みできます。
しかし、設定ファイル用途で使用したり、ある程度容量が増えてきたりすると、外部ファイルに分割したくなります。

こういった場合ファイルの分割は、Windows Script Component (WSC) の仕組みを使って実現できます。

WSC は、WSF形式のスクリプトをCOMコンポーネントとして扱えるようにするテクノロジーですが、
モニカという機能を使って、レジストリに登録すること無くコンポーネントを利用できます。

つまり、<resource>タグごとコンポーネント化することで、外部ファイルに切り出せるということです。

やり方

モニカを使ったコンポーネントの取得には、
WSHJScriptVBScript)が公開している GetObject 関数の引数に script:<wscの絶対パス> を指定します。
wscのパスは、相対パスだとエラーになります。
その他、拡張子は wsc である必要は無く xml 形式として誤りが無ければ任意の拡張子が指定可能です。(サンプルでは、拡張子を xml とします。)

sample.bat(スクリプト側) resource.xml(リソース側) は、同じディレクトリに配置して動かしています。

Workspace
├─sample.bat        
└─resource.xml      

スクリプト

簡素化のために、bat ファイルに埋め込んでいますが、処理内容はシンプルです。
バッチでプロセス環境変数に、wsc(resource.xml) のパスをsetしておいて、
JScriptで、setした環境変数を読み取っています。

<!-- :
@echo off&title %~n0&setlocal&pushd %~dp0

rem リソース(wsc)のパス
set resource_name=resource.xml
set resource_path=%~dp0%resource_name%
set resource_moniker=script:%resource_path%

rem job実行
cscript //nologo "%~f0?.wsf" %* || pause

popd&endlocal&exit /b
-->
<job>
<object id="shell" progid="WScript.Shell"/>
<script language="JScript">
WSH.Quit(function()
{
    try{
        // リソース読み込み
        var procEnv = shell.Environment("Process");
        var rc = GetObject(procEnv("resource_moniker"));
        
        // とりあえず、表示
        var result = rc.Get("sln");
        WSH.Echo(result);

        // (ここで、リソースを使ってやりたい処理など)
    }
    catch(e){
        WSH.Echo(e.name + ":" + e.message);
        return -1;
    }
    finally{
        // 表示確認のため、3秒待機
        WSH.Sleep(3000);
    }
    return 0;
}());
</script>
</job>

リソース側

<resource id="識別子"><![CDATA[]]></resource> の間が、埋め込むテキストです。
拡張子を .wscでなく、.xmlにしているのは、ダブルクリックでレジストリ登録が走らないようにするためのフェイルセーフ。

<?xml version="1.0" encoding="utf-16" ?>
<component>
<!-- 下記2行で、リソース取得関数を公開 -->
<public><method name="Get"><PARAMETER name="id"/></method></public>
<script language="JScript">function Get(id){return getResource(id)}</script>

<!-- 適当なリソース -->
<resource id="sln"><![CDATA[
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2016
MinimumVisualStudioVersion = 10.0.40219.1
Global
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
        SolutionGuid = {753BEE69-EAF9-44D4-86E7-78DDC490BA05}
    EndGlobalSection
EndGlobal
]]></resource>
</component>

あとがき

今回は、任意のディレクトリ構成でVisualStudio用のプロジェクトを作成するスクリプトで使用した方法の備忘録です。
設定ファイル程度であれば htmlfile オブジェクトから、JSONオブジェクトが取れるので.jsonで取り扱うことも出来ますが、
複数の既成フォーマットをひとまとめにしておくケースでは、テキストリソースの方が都合が良い訳です。

一応別解として、ES3程度の機能しかないJScriptでも正規表現を駆使したテクニックで、
ヒアドキュメントのような事ができるので、
<script>タグのsrc属性でリソース分割は可能ではありますが、これはランタイムで本来不要なテキストの加工が走るので好みません。

そういうわけで、WSCを使った方がパフォーマンス的にもコードの読みやすさとしても、スマートになるかと思います。

終わり。