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

趣味プログラマのメモ

【Windows】Aeroシェイク のみ無効化する(Aeroスナップ は有効)

メモ

Aeroスナップは多用するけど、Aeroシェイクを誤爆しがちなので、
シェイクの方だけ無効化したい。
これは、レジストリの設定で対応可能。

レジストリの設定

.reg ファイル(UTF-16 with BOM)を作って実行するだけ。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Explorer]
"NoWindowMinimizingShortcuts"=dword:00000001

参考

admx.help

Windows10 で、初代 MOTU UltraLite を使う(ドライバーのインストール)

はじめに

ドライバーを見つけられなくて、インストールに躓いたので簡単にメモを残しておく。
公式トップに出てくるページから、UltraLite (含む古い製品)を選択すると Firmware 項目しか出てこないけど、
サポートページの方に、置いてあるよという話。

環境

インストール方法

(2ステップだけ)

MOTU Audio Installer の対象製品

レガシープロダクトの一覧は、下記ページから確認できる。
https://motu.com/techsupport/technotes/motu-audio-installer-and-legacy-products

  • 1224
  • 1296
  • 2408
  • 2408mkII
  • 2408mk3
  • 24i
  • 24I/O
  • 308
  • 828
  • 828mkII FW/USB
  • 828mk3
  • 896
  • 896HD
  • 896mk3 FW
  • HD192
  • MicroBook
  • MicroBook II
  • Traveler
  • UltraLite
  • UltraLite-mk3 FW

おわりに

初代 UltraLite がタダ同然で入手できたので、サブPCでDACとして使おうとしたのが発端。
IEEE1394をサポートした現行マザーボードは、おそらく絶滅しているので、PCIかPCIEで増設することになるのだけど、
調べてみると、どうやらここにも落とし穴があるらしい。

自分の環境では、すんなり動いてしまったが、

といった話が見つかる。
USB2.0V+1394V-PCI は、VIA製だが、ひとまず報告されているような問題は確認できなかった。

以上。

ImageMagick で、画像を 4bit深度 bmp に変換する(減色)

メモ

Windows APILoadBitmap等、
何かしらのリソースとして4bit深度のビットマップイメージが使いたい時、
ImageMagick」と「ペイント(mspaint)」を使って作成する例。

ImageMagick の入手

ImageMagick - Download

今回は、Portable版を使う。(ImageMagick-7.0.10-59-portable-Q16-x64.zip)

変換方法

例では、ImageMagick をCドライブ直下に保存(解凍)。

コマンドは、下記の通り。

"C:\ImageMagick-7.0.10-59-portable-Q16-x64\convert" "変換元の画像パス" -depth 4 "保存先パス(拡張子.bmp)"

変換された bmp を右クリックして、
「プロパティ」「詳細」タブの「ビットの深さ」が4になっていることを確認して完了。

この時、「ビットの深さ」が4にならない場合は、
4bit深度 png を経由すると変換できる事がある。

"C:\ImageMagick-7.0.10-59-portable-Q16-x64\convert" "変換元の画像パス" -depth 4 "一時保存先パス(拡張子.png)"
"C:\ImageMagick-7.0.10-59-portable-Q16-x64\convert" "一時保存先パス(拡張子.png)" -depth 4 "4bit bmp 保存先パス"

Visual Studio のリソースエディタで読めるようにする

ImageMagick の変換だけでは、何故か Visual Studio のリソースエディタで、
「認識できないビットマップ形式です。」とエラー表示が出る。

これは、Windows標準の「ペイント」に読み込ませて、
「上書き保存」することで、解決する。

参考

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\""

WSH JScript Chakra エンジンの共存による機能制限の回避(WScript Quit 代替)

はじめに

WSH JScriptChakra を指定すると WScript Object の機能が制限される為、
WScript.Quit 関数が利用できず、戻り値を返す術が失われます。
今回は、この問題の対処例を挙げます。

前提

Windows 環境には、Windows Script Host(WSH)と呼ばれる
Node.js の様な JavaScript が動作するスクリプトの実行環境が標準搭載されています。

技術としては古いものなので、デフォルトでは ES3 程度のサポートですが、
スクリプトエンジンを Chakra に変更することでES6の機能が利用可能です。
WSH JScript Chakra を使用した ES2015(ES6) 対応 ( スクリプトエンジン まとめ )

JScriptChakra を共存させる

既定のJScript で、Chakra 用の処理をラップする形の対処法です。
WScript.Quit は、CScript でないと戻り値が機能しないので、バッチに埋め込みます。

この方法は、JScriptChakra で各エンジンが共存するので、
機能制限の掛かる箇所は、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済みですが、
大体下記のように処理しています。

  • JScript
    1. IEオブジェクトを作成
    2. 実行引数に、IEのウィンドウハンドルを設定して、Chakraエンジンで自身を起動
    3. GetPropertyでChakraのオブジェクトが設定されるまで待機
    4. ChakraのWScriptを、JScriptの定義で上書き
    5. Chakra側のmain関数を呼び出して、戻り値を受け取る
    6. プロセス同期用のフラグを折ってChakra側を終了
    7. main関数の戻り値をWScript.Quitに指定して終了
  • Chakra
    1. 実行引数に渡されたウィンドウハンドルから、IEオブジェクトを特定
    2. PutPropertyで、IEオブジェクトに this を設定
    3. プロセス同期用のフラグが折れるまで待機

追記(おそらく最適解):例外を握りつぶすと戻り値が使えるらしい

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エンジンで自身を起動し直す仕組みで、
実行すると、メッセージボックスが表示されます。

JScriptChakra のコードを埋め込む

JScript には、IEスクリプトエンジンとして利用されている経緯から
Chakra には無い、ブラウザの判別用の「条件付きコンパイル」機能が搭載されています。

これは、コメント行にコードを利用するかどうかの判定を埋め込む代物なので、
JScriptコンパイラが読み飛ばす部分(@if(0)~@end)は、処理されません。
つまり、ES6の機能を利用しても、コンパイルエラーしないという事です。

/*@cc_on

WSH.Echo("JScript で実行される範囲");

@if(0) @*/

WSH.Echo(`Chakra で実行される範囲`);

//@end

結果、ES6ベースなコードの埋め込みが実現し、
JScript で実行される範囲」から、Chakraエンジンを指定して自身を起動し直すことで、
Chakraエンジンからは、コメントアウトされていない部分だけが実行されます。

無事コマンドプロンプトを表示せずに、Chakraエンジンでスクリプトが実行されました。

おわりに

JScriptChakra のコードを埋め込む方法は、
こちらを参考にしました。
qiita.com

Chakraで再起動する処理は、コーディングに直接関係ないので
Minifierを使って1行に収めてしまいましたが、
コマンドライン引数を利用する為の処理が、そこそこ長くなっています。

WSH.Arguments は、配列型ではないので無難にforを使いましたが、
もしかすると、より短く書けるかもしれません。

おわり。