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

だいたい付箋。一口サイズのメモ帳

「サウンド」ウィンドウを開くコマンド

サウンド」ウィンドウを開くコマンド

ランチャーアプリ登録用に確認したもの。

コマンド

サウンド 設定画面

start ms-settings:sound

サウンド コントロール パネル

%windir%\system32\rundll32.exe Shell32.dll,Control_RunDLL mmsys.cpl

音量ミキサー

%windir%\System32\SndVol.exe

その他

「ファイル名を指定して実行」から起動する場合は、ms-settings:sound, mmsys.cpl だけ指定すれば良し。

C++ CLI Processクラスから HINSTANCE を取得

メモ

C++/CLI 環境で、Process クラスで起動したプログラムのインスタンスハンドルを取得する方法。
Handleプロパティが、そのまま HINSTANCE として扱える。

実装

// 「ペイント」を起動
auto proc = gcnew System::Diagnostics::Process();
proc->StartInfo->FileName = "mspaint.exe";
auto result = proc->Start() && proc->WaitForInputIdle();
if (!result)
{   // 起動に失敗
    return;
}

// インスタンスハンドルを取得
auto hInst = static_cast<HINSTANCE>(proc->Handle.ToPointer());

「AppNetworkCounter」を日本語化する手順

https://user-images.githubusercontent.com/12238431/70074333-d9233200-163d-11ea-8c0c-a25e0c81c5d4.png

はじめに

NirSoft の AppNetworkCounter v1.35 を日本語化する手順です。
現在(2019/12/09)、公式サイトには日本語向けの設定ファイルが無いので、GitHub上に公開されているもの(サードパーティ)を使います。

手順

手順は、以下の通り。

  1. 下記のリンクから、最新版のappnetworkcounter_japanese.zipをダウンロード
    github.com
  2. appnetworkcounter_japanese.zip を解凍して、
    AppNetworkCounter.exe と同じディレクトリにAppNetworkCounter_lng.iniを配置
  3. AppNetworkCounter.exe を起動して、日本語化されていれば完了

あとがき

AppNetworkCounter_lng.ini のベースになるファイルは、AppNetworkCounter.exe /savelangfile コマンドで生成できますが、
文字コードがシステムに依存しているようで、日本語環境では Shift_JIS が使用されました。

挙動が気になって Unicode(UTF-16) でも試したところ問題なく受け付けました。これは公式対応しても良い気がします。
Shift_JIS が使われて困るというわけではないものの、ふとしたことで文字化けしない文字コードの方が良いですね。
(リンク先からダウロードできる設定ファイルは、Unicode(UTF-16) 化されています。)

JScript.NET をバッチに埋め込む方法

はじめに

Microsoft製のドマイナー言語、JScript .NET をバッチファイルに埋め込んで実行する方法です。

JScript .NET は、スクリプト言語である WSHJScript の後継的な位置づけでありながら、コンパイル必須という扱いづらい言語なので、
コンパイル処理と実行を一度に処理できるように、バッチファイルに埋め込んでしまおうというお話。

実装

@if(0)==(0) echo off&title %~n0&for /f "delims=" %%i in ('certutil -hashfile "%~f0"^|find /v ":"') do (set app_hash=%%i)
set app_path=%~dp0%~n0[%app_hash%].exe
if not exist "%app_path%" (del "%~dp0%~n0[*].exe">nul 2>&1&setlocal enabledelayedexpansion
    for /f "delims=" %%i in ('where /r %windir%\Microsoft.NET jsc.exe^|sort') do (set compiler_path=%%i)
    (for /f "delims=" %%i in ('call "!compiler_path!" /nologo /out:"%app_path%" "%~f0"') do if not "%%i"=="" (echo %%i))&&pause
)
"%app_path%" %*&exit /b %errorlevel%
@end

// 以下に実装を書く
import System;

/**
 * エントリーポイント用
 */
Environment.Exit(function():int{
    var exitCode:int = 0;
    try{
        Console.WriteLine("Hello JScript.NET!!");
        Console.ReadKey();
    }catch(e){
        exitCode = int.MaxValue;
        print(e), Console.ReadKey();
    }finally{
    }
    return exitCode;
}());

あとがき

JScript .NET の長所と短所を挙げてみると。。。どうも、短所が目立っている感じがします。

  • 長所
  • 短所
    • リファレンスの整備状況が悪い
    • 日本語の情報が極端に少ない
    • 検索しようとしても、WSH版のJScriptが先に引っかかる
    • 2010年以降、アップデートされていない
    • 新しい構文(ES6)がサポートされない(そもそも、JScript .NET の文法と混在させることが不可能)

DXライブラリ向け 簡易キー入力クラス

はじめに

DXライブラリで、キー入力の開始や終了を取る際、自前で機能を用意する必要があります。
必要になるたびに作るのが面倒そうなので、キー入力クラステンプレート的なものを置いときます。
対象は、キーボードとマウスです。

昔、DxLibをラップした自作ライブラリで学習がてら作ったものから、
切り出しだけなので、気になる部分があれば、適当に調整してください。

実装

押した瞬間、押している間、離した瞬間 が取れる実装です。

ビルド環境:Microsoft Visual C++ 2015

#include <DxLib.h>
#include <array>

namespace dxlut
{
    // 入力クラス
    struct Input final
    {
        // 入力情報更新
        static bool Update() {
            Mouse::Update();
            return Keyboard::Update();
        }
        
        // 何らかのキーの入力開始
        static bool AnyKeyPress() {
            return DxLib::CheckHitKeyAll() != 0;
        }
        
        // 何らかのキーの入力中
        static bool AnyKeyDown() {
            return Keyboard::AnyDown() || Mouse::AnyDown();
        }

        // 何らかのキーの入力終了
        static bool AnyKeyUp() {
            return Keyboard::AnyUp() || Mouse::AnyUp();
        }

        // キーボード
        struct Keyboard final
        {
            typedef std::array<char, 256> KeyStateBuffer;

            // 入力情報更新
            static bool Update() {
                keyBuffer_.swap(prevKeyBuffer_);
                return GetHitKeyStateAll(&keyBuffer_.front()) == 0;
            }

            // 入力開始
            static bool IsPress(const int keyCode) {
                return keyBuffer_[keyCode] ? true : false;
            }

            // 入力中
            static bool IsDown(const int keyCode) {
                return keyBuffer_[keyCode] && !prevKeyBuffer_[keyCode];
            }

            // 入力終了
            static bool IsUp(const int keyCode) {
                return !keyBuffer_[keyCode] && prevKeyBuffer_[keyCode];
            }

            // 何らかのキーの入力開始(キーボード)
            static bool AnyPress() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (keyBuffer_[idx] != 0) {
                        return true;
                    }
                }
                return false;
            }

            // 何らかのキーの入力中(キーボード)
            static bool AnyDown() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (keyBuffer_[idx] && !prevKeyBuffer_[idx]) {
                        return true;
                    }
                }
                return false;
            }

            // 何らかのキーの入力終了(キーボード)
            static bool AnyUp() {
                for (unsigned idx = 0; idx < keyBuffer_.size(); ++idx) {
                    if (!keyBuffer_[idx] && prevKeyBuffer_[idx]) {
                        return true;
                    }
                }
                return false;
            }

        private:
            static KeyStateBuffer  keyBuffer_;
            static KeyStateBuffer  prevKeyBuffer_;
        };

        // マウス
        struct Mouse final
        {
            // 入力情報更新
            static void Update() {
                backKeyBuffer_ = keyBuffer_;
                keyBuffer_ = GetMouseInput();
            }

            // 入力開始
            static bool IsPress(const int keyCode) {
                return (keyBuffer_ & keyCode) != 0;
            }

            // 入力中
            static bool IsDown(const int keyCode) {
                return ((keyBuffer_ & keyCode) != 0) && !((backKeyBuffer_ & keyCode) != 0);
            }

            // 入力終了
            static bool IsUp(const int keyCode) {
                return !((keyBuffer_ & keyCode) != 0) && ((backKeyBuffer_ & keyCode) != 0);
            }

            // 何らかのボタン入力開始(マウス)
            static bool AnyPress() {
                return keyBuffer_ != 0;
            }

            // 何らかのボタン入力中(マウス)
            static bool AnyDown() {
                return (keyBuffer_ != 0) && !(backKeyBuffer_ != 0);
            }

            // 何らかのボタン入力終了(マウス)
            static bool AnyUp() {
                return !(keyBuffer_ != 0) && (backKeyBuffer_ != 0);
            }

        private:
            static int  keyBuffer_;
            static int  backKeyBuffer_;
        };
    };
    Input::Keyboard::KeyStateBuffer Input::Keyboard::keyBuffer_ = {};
    Input::Keyboard::KeyStateBuffer Input::Keyboard::prevKeyBuffer_ = {};
    int Input::Mouse::keyBuffer_ = 0;
    int Input::Mouse::backKeyBuffer_ = 0;

    // DXライブラリ簡易ラップクラス
    struct DxLibApp final
    {
        DxLibApp()
        {
            SetGraphMode(1024, 600, 32);
            ChangeWindowMode(TRUE);
            if (DxLib_Init() == -1) {
                throw;
            }
            SetDrawScreen(DX_SCREEN_BACK);
        }

        ~DxLibApp() {
            DxLib_End();
        }

        static bool Update() {
            return (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && Input::Update());
        }
    } _app;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    using namespace dxlut;

    // メインループ
    while (DxLibApp::Update())
    {
        // Esc 終了
        if (Input::Keyboard::IsDown(KEY_INPUT_ESCAPE)) {
            break;
        }

        // とりあえず、「キーボードのZ」と「マウス左クリック」の入力検査サンプル
        // 他のキーは、キーコードだけ変えればよし

        // Zキーの状態
        if (Input::Keyboard::IsDown(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力開始\n"));
        }
        if (Input::Keyboard::IsPress(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力中\n"));
        }
        if (Input::Keyboard::IsUp(KEY_INPUT_Z)) {
            DxLib::printfDx(_T("[Z] 入力終了\n"));
        }

        // 左クリックの状態
        if (Input::Mouse::IsDown(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力開始\n"));
        }
        if (Input::Mouse::IsPress(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力中\n"));
        }
        if (Input::Mouse::IsUp(MOUSE_INPUT_LEFT)) {
            DxLib::printfDx(_T("[Mouse L] 入力終了\n"));
        }
    }

    return 0;
}

あとがき

たまたま、DXライブラリ製の小物プログラムを改修する機会がありました。
入力周りの制御をネットで調べると意外と簡易的なものが見つからなかったので、昔のコードを掘り返し備忘録行き。

DXライブラリは、よく使いそうな便利関数も自分で用意しないといけない部分が多い印象です。
この点において、イマドキだとUnityだったり、C++ならSiv3D(OpenSiv3D)が便利関数豊富で初心者が取っつきやすい環境かなと感じています。

WSH WSF をバッチに埋め込む方法(現在時刻を読み上げるバッチファイル)

ちょっとしたメモ

タイトルの通り、wsf 形式のWSHスクリプトをバッチファイルに埋め込む方法です。
wsfを使えば、VBScriptJScript を混在させたり、
HTML の scriptタグ と同じように記述できるのでGoogle APIsから jQuery 使うようにしたりできます。
バッチに埋め込むメリットは、用途次第ということで省略。

コマンド

おまじない部分は、下記の通り。

<!-- :
@echo off
%windir%\System32\cscript.exe //nologo "%~f0?.wsf" %*
%ComSpec% /c exit %errorlevel%&goto:EOF
--->

これを駆使して、現在時刻を読み上げる機能を作ると下記のようになります。

<!-- :
@echo off&title %~n0
%windir%\System32\cscript.exe //nologo "%~f0?.wsf" %*
%ComSpec% /c exit %errorlevel%&goto:EOF
--->
<!-- :

WSH WSF をバッチに埋め込む方法

サンプル:
    現在時刻を読み上げるバッチファイル

--->
<job>
<script language="VBScript">
' 現在時刻を返すだけ の関数
Function GetDateTime()
    GetDateTime = Now
End Function
</script>
<script language="JScript">
/**
 *  @brief  エントリーポイント用即時関数
 */
WSH.Quit(+function ()
{
    var sp = WSH.CreateObject("SAPI.SpVoice");
    // 現在時刻を読み上げる
    sp.Speak(GetDateTime());
    return 0;
}());
</script>
</job>

参照

埋め込む方法は、下記から。 stackoverflow.com

WSH JScript Chakra を使用した ES2015(ES6) 対応 ( スクリプトエンジン まとめ )

はじめに

WSH JScript (wscript cscript) で使用できる スクリプトエンジン まとめです。

サードパーティーは含みません。
JavaScript限定、デフォルトで使用可能な物だけなので注意。

JavaScript エンジン について

JScript (JavaScript) だけでも、4種類ほどスクリプトエンジンがあるようです。
以下、それぞれの cscript.exe で使用する際のサンプルコマンドです。

JScript

JScript を使用する際、一般的に指定されるスクリプトエンジンです。
バージョンは、環境によって異なりますが、
現時点のOSサポートを考慮すれば、5.7 か 5.8 でしょう。

rem jscript.dll
%windir%\System32\cscript.exe //nologo //E:JScript "%~f0" %*

JScript.Compact

JScript Compact Profile (ECMA 327) で実行する、スクリプトエンジンです。
MSの情報が少ないので、詳細は未確認ですが
簡単に説明すれば、「いくつかの機能を制限して、パフォーマンス向上を図る設定を使用する」と言った感じでしょうか。
機能の制限について、少なくとも with ステートは、サポートされていないようです。

rem JScript Compact Profile (ECMA 327)
%windir%\System32\cscript.exe //nologo //E:JScript.Compact "%~f0" %*

JScript9

IE9 から使用されている、JScript9.dll をスクリプトエンジンとして指定できます。
ProgID が公開されていないので、CLSID を指定する必要があります。

ちなみに、JScript9 の 9 は、エンジンバージョンと言うわけでは無い様で、
Windows10 では、バージョン 11.0 として扱われていました。(中身は、Chakra っぽい?)

ES5ベースなので JScript と同程度の機能しか使えませんが、JScript9.dll の方が高速に動作します。
ただし、JScript 互換は完全ではなく WScript.Quit が使用できません。

rem jscript9.dll
%windir%\System32\cscript.exe //nologo //E:{16d51579-a30b-4c8b-a276-0ff4dc41e755} "%~f0" %*

Chakra

Microsoft EdgeJavaScriptエンジン です。
こちらも、ProgID が公開されていないので、CLSID を指定する必要があります。

Chakra を使用する場合は、ES2015(ES6) に対応している為、クラスなどが使用できます。
ただし、JScript9 と同様に、WScript.Quit は、使用できません。

rem chakra.dll
%windir%\System32\cscript.exe //nologo //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "%~f0" %*

Chakraを使用したスクリプト を バッチに埋め込む場合

@if 等を使用して、バッチファイルにJScriptを埋め込むこと(shebangモドキ)がありますが、
Chakra を使用する場合は、構文エラーとなってしまうため、少し工夫が必要です。

自分の場合は、以下の様にしています。

rem=0;/*
echo off&cls&title %~n0
%windir%\System32\cscript.exe //nologo //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "%~f0" %*
pause rem コンソールが、閉じないように止める
exit %errorlevel% */

JScript9 や Chakra で、戻り値を返したい場合

WScript.Quit が使えないのは、少々痛手なので、代替案です。
スクリプトをバッチに埋め込んで、戻り値をテキストでやり取りする方法が楽だと考えました。
スクリプト側で、exitcode.txt を出力し、バッチ側でexitcode.txtを読んで終了 といった流れです。

rem=0;/*
echo off&cls&title %~n0
%windir%\System32\cscript.exe //nologo //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} "%~f0" %*
rem テキストの値を戻り値にしてしまう。
set /p code=<exitcode.txt
exit %code% */

おわりに

WSH ってだけで、今更感満載のレガシーなのですが、
初期状態のWindowsで使用できる手軽さで、根強く?使われている様子。

今回のまとめは、WSH JScript で、クライアントの環境に依存せずに
ES2015 ベースのコードを使えないか調査したときの副産物です。

結果的に、ES2015 対応は行っていませんが、
TypeScript 経由で、対応できそうかなと言ったところでオチ。

参考リンク