winget が使える状態で Windows Sandbox を起動する

Windows Sandbox は、Windows 10/11 Pro 以降に搭載されている仮想環境機能だ。
一時的でクリーンな Windows 環境を素早く作成し、アプリケーションのテストやファイルの検証を安全に行うことができる。

Windows Sandbox を使うにあたって、目的の作業に必要なツールをサクッとインストールしたいことがままある。
Windows 上でツールをインストールする場合、 Microsoft Store や winget を使う事が一般的だ。
しかし、 Windows Sandbox を立ち上げてすぐの環境ではこれらを使うことができない。
加えて、素直にこれらをインストールしようにも、依存関係が満たされていないためインストールに失敗してしまう。

そこで、 Windows Sandbox の設定ファイル (.wsb) を使用して、 Windows Sandbox 起動時に winget が使える状態を整えよう…というが、今回の話。

Windows Sandbox の設定ファイル (.wsb) とは

Windows Sandbox は、XML 形式の設定ファイル (.wsb) を使用して起動時の構成をカスタマイズできる。
この設定ファイルでは、主に以下のような設定が可能だ。

  • vGPU(仮想 GPU)の有効/無効
  • ネットワークの有効/無効
  • 共有フォルダの設定
  • メモリ使用量の制限
  • ログオン時のコマンド実行

詳細な設定オプションについては、以下のマイクロソフト公式ドキュメントを参照:

今回は、上記のうち「ログオン時のコマンド実行」の機能を利用する。

winget をインストールするログオンコマンド

続きを読む

GitHub 上のソースコードの一部を Gist のように埋め込む Cloudflare Workers

本記事は Cloudflare Advent Calendar 2024 25日目の記事だ。
空いていたので埋めちゃおう。

TL;DR

gist-it が動かなくなっちゃったので、 Cloudflare Workers で実装してみた話

ブログに GitHub 上のコードを埋め込みたい

ブログでコードの解説記事を書いていると、 GitHub 上のコードの一部を GitHub Gist のように埋め込んで表示したくなることがよくある。

以前は Gist-It というサービスを利用させていただいていたのだが、 ホストしている Google App Engine で Python 2.7 がサ終した 1 せいか、動作しなくなってしまっている。

欲しい機能は、処理内容は GitHub のソースコード取ってきて、 <pre> タグに書き込んでシンタックスハイライトを適用するような、割と単純でステートレスなもの。
このため、 Cloudflare Workers で実装してみた。

使い方

続きを読む

Power Automate で key-value Array ⇔ Object (Dictionary) を相互変換して Office Script の呼び出しを節約する

本記事は、 Microsoft Power Automate - Qiita Advent Calendar 2024 - Qiita シリーズ3 の 21日目 の記事だ。
…本当は、 シリーズ1 の 19日目 に投稿しようとしてたのだけれど、諸事情で記事更新ができず、代理投稿されてしまったので、改めて投稿し直している。

今回は、 Power Automate に於いて、連想配列の形で情報を持たせた Object と、 key-value Array の間を相互変換する方法を解説する。

Premium コネクタやループ処理などは使用せず、 O(1) オーダーのなるべく少ないステップ数で Object ⇔ Array 配列の相互変換させよう。

昨年の Power Automate Advent Calendar 2023 と同様、ステップ数を節約するテクニックの話題だ。

key-value Array ⇔ Object の変換目的

Array から Object に変換すると、 Power Automate の数式で variables('val-name')['property-name'] とアクセスできる。
このため、ループ処理で一旦統計したデータを後から参照させる場合などで都合が良い。

一方で Object から Array にしておくと、 選択アクション を使って 1ステップ で反復処理が行えるため、処理ステップ数を節約できる。

ほか活躍できる具体例として、Array にすることで Office Script との間での辞書型の情報の受け渡しが可能になることが挙げられる。

Office Script との引数・戻り値の受け渡しには key-value Array がよい

スクリプトのユーザー入力を取得する - Office Scripts#入力の制限 にあるように、 Office Script の入出力に設定する『型』は、リテラル型とそれらによる配列・オブジェクト型に限られる。
TypeScript で言う Indexシグネチャで表現できるディクショナリパターン の型を、 Office Script の main 関数のパラメータに使おうとすると、 Type literal contains invalid type 'Unrecognized' エラーになってしまうのだ。 1

function main(
  workbook: ExcelScript.Workbook,
  arg1: { [key: string]: { prop1: string, prop2: string } }
) { // <- Parameter type error for parameter 'arg1: TypeLiteral': Type literal contains invalid type 'Unrecognized'.
    const val: { [key: string]: { prop1: string, prop2: string } } = {}; // <- ok
}

幸い引数に object 型を設定することはできるが、型情報が綺麗サッパリ消えてしまうので、型アサーションに頼る必要が出てくる。
加えて、それでも返り値には object 型を設定できない。

function main(
  workbook: ExcelScript.Workbook,
  arg1: object
) {
  for (const key of Object.keys(arg1)) {
    const t = arg1[key] as { prop1: string, prop2: string };
  }
  return arg1; // <- Return type error: 'Object' is not supported. Try using an interface or type literal instead
}

つまり、 HTTP 要求トリガーbody('HTTP_要求').inputs.headers のような、任意のプロパティ名のオブジェクトで渡されるような情報を、 Office Script で処理して返しづらい。

このため代わりに、 { key: string, value: TYPE }[] な key-value 配列に変換して受け渡すことで、型情報を維持したまま Office Script との間で辞書型の情報を受け渡せるわけだ。

function main(
  workbook: ExcelScript.Workbook,
  arg1: { key: string, value: { prop1: string, prop2: string } }[]
): { key: string, value: { prop1: string, prop2: string } }[] { // <- ok
  return arg1; // <- ok
}

Power Automate からの Office Script の呼び出しには 3回/10秒 という制限があるので、 Power Automate の同一フロー中に何度も呼び出したり、ましてのフロー内のループ中に呼び出す事はできない。
このため、 key-value Array を引数に Office Script を 1回 呼び出してその中でまとめて処理をし、 Power Automate 側で key-value Array から辞書型のオブジェクトに戻すのが良いだろう。

相互変換の実装

続きを読む

Rust で Windows API のグローバルフック

本記事は、 Rust Advent Calendar 2024 シリーズ3 の 20日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 20日目 の記事としても登録させてもらっている。
遅刻です。申し訳ない。

今回は、やや実践的な例として、 Rust で Windows API の グローバル フック を使って、各ウィンドウに届くマウスやキーボード・ウィンドウメッセージをダーッとリアルタイムで表示するコードを書いてみよう。

フックDLLでメモリリークやセグメント違反を引き起こすとシステム丸ごと死にかねないし、フックした情報を表示するためにプロセス間通信やマルチスレッドの処理が必要になるなど、割と Rust 向きな例ではなかろうか。

フックとは

Win32 アプリケーションでは、各ウィンドウやコントロールがそれぞれイベントハンドラ(プロシージャ)を持ち、これが届いたメッセージを処理することで様々な機能を振る舞わせる。
「フック」とは、本来のプロシージャに届くはずの処理を先に引っ掛けて(フックして)、処理を間に挟んでから本来のプロシージャに返したり、あるいは処理を奪ってしまう機能だ。

グローバル フック は、同じ PC 内の権限的に許されるあらゆるプロセスのスレッドに対して、フックをねじ込む機能だ。
キーロガーなどのウイルスや、クリップボード監視のソフトなどでよく使われている(と思う)。

グローバルフックした場合、フック対象それぞれのプロセス毎に、フックプロシージャを定義した DLL をロードさせ、そのプロシージャを呼び出させる。
つまり、フックされたプロセス毎に DllMain が呼ばれるし、メモリ空間も独立する。
標準出力も、フックされたプロセスのものが利用されるので、例えばフックプロシージャで println! しても、フックを登録したプロセスではなくて、フックされたプロセス側の標準出力に書き込まれるわけだ。

graph LR
    subgraph caller[呼び出し元 exe]
        D0[DLL]
    end
    subgraph sub1[フック対象プログラム1]
        D1[DLL]
    end
    subgraph sub2[フック対象プログラム2]
        D2[DLL]
    end
    D0 -->|"登録"| D1
    D0 -->|"登録"| D2
    D1 -->|"println!"| cfor1@{ shape: f-circ }
    D2 -->|"println!"| cfor2@{ shape: f-circ }
    cfor1 --> sub1
    cfor2 --> sub2

このため、フックしたメッセージを登録元プロセスにて表示するためには、スレッド間参照などは使えず、プロセス間通信などを使う必要がある。
今回は、名前付きパイプで登録元プロセスに情報を渡してみる。

graph LR
    subgraph caller[呼び出し元 exe]
        D0[DLL]
    end
    subgraph sub1[フック対象プログラム1]
        D1[DLL]
    end
    subgraph sub2[フック対象プログラム2]
        D2[DLL]
    end
    D0 -->|"登録"| D1
    D0 -->|"登録"| D2
    D1 -->|"名前付きパイプ等"| caller
    D2 -->|"名前付きパイプ等"| caller

名前付きパイプによるプロセス間通信

続きを読む

AutoHotKey v2 で 令和の ThumbSense

本記事は、 Windows Advent Calendar 2024 18日目 の記事だ。
思いっきり遅刻してしまって申し訳ない。

突然だが、 ThumbSense を覚えているだろうか?
2002年に SONY が発表した、ノートPCのタッチパッドを用いて、手をホームポジションから動かさずに、マウス操作や様々なショートカットを起動するユーティリティツールだ。
(本家, 窓の杜の紹介記事)

当時はその革新的な操作体験で大いに注目されていたと記憶している 1 し、 ThumbRemap や NewtonPad などのインスパイアされたツールがいくつも登場していた。

しかし、当時のこれらの実装は Synaptic または ALPS 製のタッチパッドのドライバーをフックして実装されていた。このため、令和となった現代、 Windows 10 や Windows 11 が入っているような PC では動かない。

現在流通しているノートPCのタッチパッドは、Windows 8.1 で追加され Windows 10 で強化された、 USB 等の HID プロファイルに基づいた実装になっている。

先日の記事 の通り、 RawInput で HID の情報を拾えばかなり細かくタッチパッドの状況がとれる。
AutoHotKey 使えば、 ThumbSense のような実装もそこまで難しくないのでは…?

…と思って AutoHotKey v2 で実装してみたのが、本日の記事になる。

ThumbReSense のインストール

GitHub の advanceboy/ThumbReSense-ahk のリリースページ から、最新の exe ファイルをダウンロードして、起動するだけ。

SmartScreen の警告が出る場合は、 exe ファイルを右クリックして、セキュリティのブロック (ZoneId) を解除しよう。

また、 AutoHotKey v2 用のソースもリポジトリにあるので、こちらをダウンロードしてインストール済みの AutoHotKey v2 で起動しても OK だ。

常用するなら、 Windows のスタートアップフォルダにでも突っ込んでおけば PC 起動時に自動で起動するようになる。

AutoHotKey の制限として、通常タスクマネージャなどの管理者特権で動くソフト上では機能しないのだが、 ThumbReSense の実行ファイル (またはスクリプトを起動する AutoHotKey) 自体を管理者権限として実行すればこの制限を回避できる。
自動起動させたい場合、タスクスケジューラを使って、ログオン時に管理者権限として起動する設定にしておくと良いだろう。

残念ながら、 Windows Sandbox やリモートデスクトップでは、ホットキーを機能させる方法がなさそうだ。

使い方

続きを読む

Rust と Win32 API RawInput で HID の TouchPad を深堀り

本記事は、 Rust Advent Calendar 2024 シリーズ1 の 17日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 17日目 の記事としても登録させてもらっている。

Win32 API の RawInput を、先日紹介した Rust + windows-rs を使って呼び出し、 USB/Bluetooth HID の生入力情報を読み取っていきたい。

PC にはキーボードやマウス以外にも、スタイラスやタッチパッド等々の多くの入力デバイスが繋がるが、通常 Windows アプリにはひとつの「マウス」または「キーボード」と抽象化された状態で情報(ウィンドウメッセージ)が届く。

生入力… もとい RawInput を使うと、複数のマウス・キーボードや、任意のヒューマンインターフェイスデバイス (HID) などの、より低レベルなメッセージを受け取れるようになる。

受け取れる情報は以下の3種類。

  • マウスからの RawInput
  • キーボードからの RawInput
  • マウスやキーボード以外の、任意の HID からの RawInput

マウスやキーボードの RawInput は Windows 側で使いやすく整形された情報を取得できる。
ゲームなどでよく使われる事もあり、サンプルも数多く見つかるだろう。

本記事では、このうち最後の「任意の HID からの RawInput 情報の取得」について、高精度タッチパッドを例に簡単に説明していく。

Rust 書き始めてまだ数週間なので、あまり Rust らしい書き方になってないかもだが、その点はご容赦を。

HID プロトコルとは

続きを読む

毎日最初のロック解除時に特定の URL を開くためタスクトレイに常駐する PowerShell スクリプト

シェルスクリプト&PowerShell Advent Calendar 2024 の 15日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 15日目 の記事としても登録させてもらっている。

電子タイムカードの打刻など、毎日出勤時に PC で特定の Web サイトを操作する事を強要されることは無いだろうか?
その作業習慣が血肉となるまで魂に刻み込まれるまで飼い慣らされていないと、頻繁に操作を忘れてしまう。

普段 PC をシャットダウンしているのであれば、スタートアップにその Web サイトの URL を登録しておくことで、 PC ログイン時に自動的にそのページが立ち上げられるので、やり忘れを防止できる。

しかし、普段 PC をスリープしっぱなしな運用にしている場合、朝初めてPCを立ち上げ(スリープ解除)した際に、特定のページを開かせるのは意外と難しい。

そこで、 PC のタスクトレイに PC のロック解除イベントを監視する PowerShell スクリプトをタスクトレイに常駐させ、「その日最初のロック解除」の時に特定の URL を開く仕組みを作成してみた。

導入手順

続きを読む

Rust で Win32 API ことはじめ

本記事は、 Rust Advent Calendar 2024 シリーズ3 の 14日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 14日目 の記事としても登録させてもらっている。

Rust で Win32 API を叩くにあたって、最初に知っておきたい情報をまとめておく。

Win32 API を呼ぶ手段

C# の P/Invoke のように一つ一つの API をソースコード上で定義してリンクすれば、呼び出せなくはない。 1

しかしそれは流石に面倒なので、 Microsoft による windows-rs のクレートを使うのが基本となる。

windows-rs とは

windows-rs は、 Microsoft 自身が Windows API のメタデータから生成されたコードを用いて、 Rust から Windows API を呼び出しやすくするクレートを提供するプロジェクトだ。
その仕組みの通り、 Win32 API のほぼ全てに加え、 COM API や WinRT もその多くがカバーしている。

大まかな情報は、以下のページにまとまっていて基本的にはこれを読み進めればよい。

しかしそれではわざわざ記事を書く必要性が薄いので、この記事では Win32 API コードを書くにあたって、最初に知っておきたい情報をまとめておこう。

なお、後述するが windows-rs は COM や WinRT の API もカバーしており、それぞれ呼び出し方にコツがある。
すべてを解説すると分量が多いので、本記事では Win32 API の範囲に限って説明する。


ところで、↑のドキュメントのドメインである kennykerr.ca って誰のやねんって話だが、 Microsoft のエンジニア らしい。
Microsoft 公式マニュアルが個人名のドメインに置かれているってどうなのと言う気もせんでもないが、元々個人の趣味プロジェクトだったのかな…?

また、 2024年12月現在最新版が 0.58.0 と、セマンティックバージョン的にもまだ破壊的変更が入りうるものだ。
最近こそ更新は落ち着いてきているものの、以下の情報が今後変わりうることはご留意いただきたい。

windows クレート と windows-sys クレートの使い分け

続きを読む

自動で最新状態を維持! Docker Compose でコンテナのイメージを定期的に更新・再起動する方法

本記事は、 Docker/コンテナ仮想環境 Advent Calendar 2024 8日目の記事だ。

「Docker は開発向けの環境だ、運用するなら K8s などのコンテナオーケストレーションツールを使え!」…とひとは言う。
しかし、 DB やアプリ等々の複数のコンテナをひとつのマシンで動かすなら、 Docker Compose でビルドまで担わせてしまう手軽さと手っ取り早さはなかなか捨てがたい。

趣味の範囲や、チームの範囲でしか使わず、そんながっつり作り込んだシステムでも無ければ、ベースイメージが更新される度に自動的にコンテナを差し替えてしまいたくなる。
そんな状況で、実行しているイメージやビルドするベースイメージに更新があった場合のみ、自動でコンテナを Recreate して再アップさせる cron ジョブを考えてみる。

Compose で定期 pull とビルドしてイメージの更新があったら再 up する cron コマンド

cd /path/to/dirname/; { docker compose --ansi never pull --no-parallel; docker compose --ansi never --progress=plain build --pull; } 2>&1 | bash -c "tee >( logger -i -t user/docker-auto-rebuild -p user.info )" | grep -E '\s+Pull complete\s*$|^#[0-9]+\s+resolve\s+' && docker compose --ansi never up -d 2>&1 | logger -i -t user/docker-auto-recreate -p user.info

こんなコマンドを、 cron に登録してやろう。

動作確認したバージョンは、 Docker Engine v27.3.1, Docker Compose vv2.29.7 だ。

$ docker version --format "Client: {{.Client.Version}}, Server: {{.Server.Version}}"
Client: 27.3.1, Server: 27.3.1
$ docker compose version
Docker Compose version v2.29.7

実行ログは journalctl を使って以下のように実行したら見れるぞ。

$ journalctl -t user/docker-auto-rebuild -t user/docker-auto-recreate --since "1day ago"

続きを読む

docker の snap パッケージをプロキシ環境で使う方法と、 compose で build エラーになる話

本記事は、 Docker/コンテナ仮想環境 Advent Calendar 2024 - Qiita 5日目の記事だ。

Linux で docker をインストールする場合、どのようにしているだろうか?
OS 標準のパッケージマネージャーからのインストールが一般的? それとも、 Docker 公式のリポジトリ (Install - Docker Docs) を使っているだろうか?

そんな docker インストールする方法のひとつに Snap (Snapcraft) がある。

Snap (Snapcraft) とは

Snap (Snapcraft) は、Canonical が開発・管理している、アプリケーションをパッケージ化して配布するためのシステムのひとつだ。 Canonical は Ubuntu を支援している企業だが、 Ubuntu 以外の多くの主要なディストリビューションでも Snap を利用できる。

依存関係を含む一式がコンテナ化されており、異なる Linux ディストリビューション間で共通のパッケージで動作するのが特徴だ。 サンドボックス化したファイルシステム内でインストールしたアプリケーションを動かすという、セキュリティ面の特徴もある。

snap 版 docker は、 /home/ 以下のファイルしか参照できない強い制限 1 や、インストール時に docker グループを作成してくれない制限があるが、それ以外はわりと問題なく動く。

Snap 版 docker に於けるプロキシ設定手順

プロキシの設定さえ適切に行えば、 snap 版 docker もプロキシ環境下で動作する。

基本的な設定箇所は、 Docker DaemonDocker CLI の設定と同じだが、前述のサンドボックス化の関係で、記述するファイルの場所が異なる。

具体的には

  • /etc/docker/daemon.json の替わりに /var/snap/docker/current/config/daemon.json
  • ~/.docker/config.json の替わりに ~/snap/docker/current/.docker/config.json

をそれぞれ書き換える。

特に後者 (~/snap/docker/current/* 以下) については、一度そのユーザーで何らかの docker コマンド (後述の例では docker info) を実行してから設定しなくてはならない。
そうしないと、フォルダが Snap サンドボックスへマッピングされないからだ。

では、インストールからの手順を追ってみよう

続きを読む