tmytのらくがき

個人の日記レベルです

wslのpathにある実行ファイルをwindowsから実行できるやつを作った

WSLって歴史的経緯で今も bash.exe で起動ができるけど、 bash.exe で起動したときは chsh で設定されたシェルではなく常にbashが起動してしまう。たぶん内部的に /usr/bin/bash を実行してるんだとおもう*1

wsl を呼べば chsh で設定されたシェルが起動はするのだけどせっかくなので zsh.exe を起動するとデフォルトのWSL環境でzshが実行されるようなやつを作ってみました。

github.com

やっていることはarg[0]からファイル名を取り出して拡張子を除去、引数部分は無加工のまま受け取ってそれらをくっつけてWSLプロセスを起動。 実行ファイルの名前を変えると*2起動するWSLプロセスが変わる仕組みです。busyboxみたいな挙動ですね。

せっかくなのでWSLでプロセスを起動したりすることについて残しておきます。

WSL内でのプロセスの実行

WSL内でプロセスを実行するには大昔は非公開APIをCOM経由で呼ばないといけなかったのだけど、いまではちゃんと公開APIが用意されているのでそれを呼ぶだけ。

プロセスの実行方法は2種類用意されていて

  • 標準入出力をパイプで渡してhProcessを返すパターン
  • 現在実行中のプロセスの標準入出力を使ってプロセスが終了するまでAPIが返ってこないパターン

コンソールを持たないプロセスの場合とかは前者、コンソールでWSLプロセスが終了するまで制御を返さなくていいなら後者でいいと思う。

今回の場合は単純にWSL内でプロセスが実行できて終了すれば自分自身も終了するので後者。

docs.microsoft.com

このAPIに、実行したいディストリビューションの名前、実行したいパスなどを指定するだけでWSLでプロセスが実行できるとても簡単。

ひとつ問題があって、ドキュメントには wslapi.lib をリンクせよ。と書いているのだけどこれがSDKになぜか含まれていない。なぜ含まれていないのかは謎だけど、実際なぜか含まれていない。 しかたないので、wslapi.dll をダイナミックリンクして使いましょう。

デフォルトディストリビューションの解決

ドキュメントを見てもデフォルト設定のディストリビューションがどれなのかを取得することはどうやらできなさそうです。これはレジストリを見ると解決できます。

WSLに関する設定は HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss 配下に収まっています。ここの、DefaultDistributionに書き込まれている名前でサブキーをたどると そこにデフォルト設定になっているディストリビューションの情報が埋まっています。

WslLaunch*ディストリビューションの名前を必要としているので、サブキーから DistributionName の値を読むことでデフォルト値が解決できます。

おしまい

こんな感じでWSLのプロセスがWindows側から起動できるそうです。

zshが起動したいためだけに作ったけれども、python.exeとかgrep.exeとか用意したらなかなか楽しくなってきた。

*1:調べてないです

*2:実行ファイルをコピーしてリネームとか、ハードリンクするといいと思います。シンボリックリンクだとExplorerがリンク先の実行ファイルを起動してしまってうまく動かない。