Windows カスタムURLスキームの設定方法(URLからアプリを起動する)
メモ
ブラウザからローカルのアプリケーションを起動するには、カスタムURLスキームを利用する。
Windows では、レジストリの設定により実現できる。
レジストリの設定
任意のアプリ(MyApp.exe)を登録する例
下記の設定で、myapp:
が認識されるようになる。
実行引数には、URL文字列が入るので適当なパーサーでパラメータを取り出して使う。
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\MyApp] @="URL:myapp" "URL Protocol"="" [HKEY_CLASSES_ROOT\MyApp\shell] [HKEY_CLASSES_ROOT\MyApp\shell\Open] [HKEY_CLASSES_ROOT\MyApp\shell\Open\Command] @="\"C:\\Program Files\\MyApp\\MyApp.exe\" \"%1\""
レビュー: Razer Ornata を普段使いした雑感
メモ
Razer Ornata を普段使いした感想。
Razer Ornata - Japanese | razer.com | Razer 日本
- 経緯
- 安物キーボードを2年以上使っているので、気分転換したくなった
- パンタグラフからの移行なので、薄型のキーボードを探していた
- Razer Ornata は、型落ちで安く入手できた(打鍵感は Chroma や V2 と同じはず)
良かった点
気になった点
その他私見
- 打鍵時のクリック音は、それなりに大きい
- キートップが摩耗しても、メカニカルと違い交換部品の入手が厳しい
- ボディは非金属製なので、無茶な使い方をすると歪むかも
- キーキャップは、光沢感の無いマットな仕上がり
→ テカリが目立ちそう - 底打ちによる反響音は無い。メンブレン特有の音。
総評
一言でいえば、クリック音の鳴るメンブレンキーボード。
クリック感のあるスイッチが好みであれば、悪くない。
メンブレンキーボードとして見ると、やや高級。
メンブレンに慣れていれば、抵抗無く使えると思う。
Razerのキーボードとしては安価なのでブランド目的なら、選択肢としてはアリ。
WSH JScript Chakra エンジンの共存による機能制限の回避(WScript Quit 代替)
はじめに
WSH JScript に Chakra を指定すると WScript Object の機能が制限される為、
WScript.Quit
関数が利用できず、戻り値を返す術が失われます。
今回は、この問題の対処例を挙げます。
前提
Windows 環境には、Windows Script Host(WSH)と呼ばれる
Node.js の様な JavaScript が動作するスクリプトの実行環境が標準搭載されています。
技術としては古いものなので、デフォルトでは ES3 程度のサポートですが、
スクリプトエンジンを Chakra に変更することでES6の機能が利用可能
です。
WSH JScript Chakra を使用した ES2015(ES6) 対応 ( スクリプトエンジン まとめ )
JScript と Chakra を共存させる
既定のJScript で、Chakra 用の処理をラップする形の対処法です。
WScript.Quit は、CScript でないと戻り値が機能しないので、バッチに埋め込みます。
この方法は、JScript と Chakra で各エンジンが共存するので、
機能制限の掛かる箇所は、JScript側で関数化する等の対処で回避可能になります。
※ 例えば、GetObject等のChakraでは未定義となる関数は、JScript 経由で利用できます。
0</* :: @cscript /nologo /E:JScript "%~f0" %* @rem 戻り値の確認用 @echo.ExitCode:%errorlevel%&pause @exit /b %errorlevel%&*/0;//@cc_on @if(0) // // Chakra // // エントリーポイント用の関数(プロセスの戻り値を返す) function main() { // コンソールに表示 const msg = `${WSH} for Chakra`; WSH.Echo(msg); // JScript側の関数を呼ぶ const r = JS.hoge(); // 強制終了するなら、例外を投げる //throw "quit"; // もしくは、早期リターン //return; // ポップアップを表示 // ActiveXObject は未定義なので、CreateObject を使う const shell = WSH.CreateObject("WScript.Shell"); shell.popup(msg); // 戻り値 return r; } function fuga() { WSH.Echo("fuga"); } var quit=!1;let item,ie,w=WSH.CreateObject("Shell.Application").Windows(),i=0; for(;i<w.Count;i++)if((item=w(i))&&item.hWnd==WSH.Arguments(0)){ie=item;break} for(ie.PutProperty("@",this);!quit;)WSH.Sleep(1e3);/*@end @cc_on for(var ckr,ie=WSH.CreateObject("InternetExplorer.Application"),sh=WSH.CreateObject("WScript.Shell"), p=sh.Exec('cscript /E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "'+WSH.ScriptFullName+'" '+ie.hWnd);!(ckr=ie.GetProperty("@"));) {if(0!=p.Status){for(;!p.StdErr.AtEndOfStream;)WSH.StdErr.Write(p.StdErr.Read(256));ie.Quit(),WSH.Quit(p.ExitCode)}WSH.Sleep(1e3)} (this.CKR=ckr).JS=this,ckr.WScript=WSH,ckr.WSH=WSH,ie.Quit(),r=CKR.main(),ckr.quit=!0,WSH.Quit(r); // // JScript // function hoge() { // Chakra側の関数を呼ぶ CKR.fuga(); return 123; } @*/
仕組み
条件付きコンパイル
機能を使って、1つのスクリプト内に
エンジン毎(JScript, Chakra)で実行されるコードを共存させています。
また、プロセス間でオブジェクトを共有するために、
InternetExplorer
Object の PutProperty / GetProperty
を利用しています。
該当部分は、コーディングに直接関係無いのでMinify済みですが、
大体下記のように処理しています。
追記(おそらく最適解):例外を握りつぶすと戻り値が使えるらしい
2022/05/28:
例外をキャッチすれば正しく戻り値が扱えるという話を見つけました。
実際試してみると、普通に扱えているようなので、これが最適解でしょう。
WSHでES2015を利用するベストプラクティス - Qiita
戻り値を確認するため、exit /b
で戻り値を設定するバッチに、スクリプトを埋め込みます。
0</* :: @%windir%\System32\cscript.exe /nologo /E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "%~f0" %* @echo 戻り値は、%errorlevel%です。&pause @exit /b %errorlevel%&*/0; // エントリ let global_result=(()=>{ // ポップアップを表示 // ActiveXObject は未定義なので、CreateObject を使う const shell = WSH.CreateObject("WScript.Shell"); shell.popup(`${WSH} for Chakra`); return 123; })(); try {WScript.Quit(global_result); }catch(e){// JavaScript runtime error: Object doesn't support this action }
おわりに
一般的に、外部から呼び出されることを想定するプログラムは、
戻り値から、エラー原因を特定できるようにしています。
Chakra を指定したスクリプトでは、スクリプトが失敗しても
戻り値から判断できない状況でしたが、これで一件落着?でしょうか。
元々 Chakra を指定する事自体が、仕様の穴をつくような方法なので、
回りくどい対応を取らざる得なくなる事もありますが、
それを差し引いても ES6 が利用できる点は大きいかと思います。
参考
JScript Chakra wscriptで、ECMAScript 2015 (ES6) を利用する
はじめに
wscript を利用する際に、Chakra エンジンを指定する方法です。
cscript で JScript を利用する場合、Chakra エンジンを指定するために
バッチファイルと組み合わせる方法がありますが、
wscript ではコマンドプロンプトの画面が不要なので、非表示で起動する方法です。
方法
必要なコードを先に載せます。
.js
もしくは .jse
形式で保存して、そのまま実行可能です。
//@cc_on for(s='"'+WSH.ScriptFullName+'"',i=0;i<WSH.Arguments.length;i++)s+=' "'+WSH.Arguments(i)+'"';WSH.CreateObject("WScript.Shell").Run("wscript /E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "+s)@if(0) // 引数を表示 let args=[]; for(let a=WSH.Arguments,c=0;c<a.length;c++)args.push(a(c)); WSH.Echo(`実行引数の数:${WSH.Arguments.length}\n${args.join("\n")}`); //@end
もしくは、コマンドライン引数を利用しない場合、もう少し短くなります。
//@cc_on WSH.CreateObject("WScript.Shell").Run('wscript /E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "'+WSH.ScriptFullName)@if(0) // 適当にコードを書く const echo = ()=>WSH.Echo("Hello WScript Chakra"); echo(); //@end
JScript エンジンで実行された後、Chakraエンジンで自身を起動し直す仕組みで、
実行すると、メッセージボックスが表示されます。
JScript に Chakra のコードを埋め込む
JScript には、IEのスクリプトエンジンとして利用されている経緯から
Chakra には無い、ブラウザの判別用の「条件付きコンパイル」機能が搭載されています。
これは、コメント行にコードを利用するかどうかの判定を埋め込む代物なので、
JScriptコンパイラが読み飛ばす部分(@if(0)~@end)は、処理されません。
つまり、ES6の機能を利用しても、コンパイルエラーしないという事です。
/*@cc_on WSH.Echo("JScript で実行される範囲"); @if(0) @*/ WSH.Echo(`Chakra で実行される範囲`); //@end
結果、ES6ベースなコードの埋め込みが実現し、
「JScript で実行される範囲」から、Chakraエンジンを指定して自身を起動し直すことで、
Chakraエンジンからは、コメントアウトされていない部分だけが実行されます。
無事コマンドプロンプトを表示せずに、Chakraエンジンでスクリプトが実行されました。
おわりに
JScript に Chakra のコードを埋め込む方法は、
こちらを参考にしました。
qiita.com
Chakraで再起動する処理は、コーディングに直接関係ないので
Minifierを使って1行に収めてしまいましたが、
コマンドライン引数を利用する為の処理が、そこそこ長くなっています。
WSH.Arguments は、配列型ではないので無難にforを使いましたが、
もしかすると、より短く書けるかもしれません。
おわり。
V言語 vlang コンソールで入力待ちする
メモ
・OS 非依存
標準入力で待機する。
import os fn main() { // 入力待ち os.get_line() }
・Windows 環境
pause
コマンドで待機する。
import os fn main() { // 入力待ち os.system('pause') }
WSH WSF JScript・VBScript で、YAML をパースする方法(js-yaml)
JScript や VBScript で yaml ファイルをパースしたいとき、
wsf形式と外部パッケージのjs-yaml
で、簡単に実現できます。
github.com
実装
yamlファイル。(sample.yaml)
文字コードは、SJISを使用。
# 設定ファイル config: title: "AppName" width: 1280 height: 720
wsf形式が関連付けされていない環境があるので、
サンプルは適当なバッチに埋め込んで使います。
<!-- : @setlocal&pushd %~dp0 @cscript //nologo "%~f0?.wsf" %* || pause @popd&endlocal&exit /b --> <job> <script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.14/es5-shim.min.js" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.14/es5-sham.min.js" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.13.1/js-yaml.js" /> <object id="shell" progid="WScript.Shell" /> <object id="fso" progid="Scripting.FileSystemObject" /> <script language="JScript"> WSH.Quit(function() { try{ // 読み込み var yamlFile = fso.OpenTextFile("sample.yaml", 1, true); var yamlText = yamlFile.ReadAll(); yamlFile.Close(); var doc = jsyaml.load(yamlText); // 表示 WSH.Echo(doc.config.title); WSH.Echo(doc.config.width); WSH.Echo(doc.config.height); // Enter入力待ち WSH.StdIn.ReadLine(); } catch(e){ WSH.Echo(e.name + ":" + e.message); return -1; } return 0; }()); </script> </job>
VBScript 版
<script language="VBScript"> ' 読み込み Set yamlFile = fso.OpenTextFile("sample.yaml", 1, True) yamlText = yamlFile.ReadAll yamlFile.Close Set doc = jsyaml.load(yamlText) ' 表示 WSH.Echo(doc.config.title) WSH.Echo(doc.config.width) WSH.Echo(doc.config.height) ' Enter入力待ち WSH.StdIn.ReadLine ' 解放 Set yamlFile = Nothing Set doc = Nothing </script>
仕組み
js-yaml
では、ES5に対応した環境が求められますが、
wsf 形式は、ES3程度の機能しか使えないのでes5-shim
ライブラリを使って
擬似的にES5環境を扱えるようにします。
読み込んだ後は、jsyaml
オブジェクトを扱うだけです。
その他
オフライン環境で使いたい場合など、
ライブラリの参照にCDNを使いたくなければ、ローカルに保存して使いましょう。
<script src="./es5-shim.min.js" /> <script src="./es5-sham.min.js" /> <script src="./js-yaml.js" />
以上、おわり。
WSH JScript で、高精度に処理時間を計測する(Performance API)
はじめに
JScriptで、スクリプトの処理時間を計測するとき、
Date オブジェクトを使って計測することがありますが、これはミリ秒単位の精度です。
厳密な速度計測が不要であれば、ミリ秒もあれば事足りますが、
より精度の高いマイクロ秒単位が必要であれば、
Web API (Performance API) の Performance インターフェースを使います。
実装
計測対象の関数は、ここから拝借。
フィボナッチ数を出力する関数を作る - Qiita
function do_something() { var fib = function (n) { return n > 2 ? fib(n - 1) + fib(n - 2) : 1; }; fib(33); }
Performance インターフェースによる計測
JScript環境の、Performance インターフェースは、
JSON オブジェクト等と同様で、htmlfile オブジェクトから取得できます。
WSH.Quit(function() { try{ // Performance を取得 var htmlfile = WSH.CreateObject("htmlfile"); htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=Edge"/>'); var performance = htmlfile.parentWindow.performance; htmlfile.close(); // 計測 var startTime = performance.now(); do_something(); var endTime = performance.now(); // 結果 // 浮動小数が得られる。小数点以下が、マイクロ秒。 // (小数第1位までしか得られない?) WSH.Echo((endTime - startTime) + " ms"); } catch(e){ WSH.Echo(e.name + ":" + e.message); return -1; } return 0; }());
過去の手法
Date オブジェクトによる計測
WSH.Quit(function()
{
try{
// 計測
var startTime = new Date();
do_something();
var endTime = new Date();
// 結果(※ これでは、ミリ秒に丸められた結果しか得られない)
WSH.Echo((endTime.getTime() - startTime.getTime()) + " ms");
}
catch(e){
WSH.Echo(e.name + ":" + e.message);
return -1;
}
return 0;
}());
その他メモ
バッチコマンドの計測であれば、powershell の Measure-Command が手軽です。
powershell -c (Measure-Command { (ここに計測するコマンド) })