Windows
VisualStudioCode

Windowsでファイルを関連付けから開く際、引数として親フォルダを渡す


環境

Windows7 64bit


動機


  • Visual Studio Codeで関連付けからファイルを開く時、既にウィンドウが開いている場合、同じウィンドウ内で開く


    • 既にワークスペースが開いていてもお構いなし


      • 対象ファイルの親ディレクトリがワークスペースとして開いている場合は、そこで開いてアクティベートしてはくれる



    • いったいどこでなにが開いてるんだかわけわかんなくなる

    • 全てのファイルを、適切なワークスペースで開いてほしい


      • 子ウィンドウがじゃんじゃん増えてもいいから






余談:Visual Studio Codeのワークスペースとは?


  • 作業を行うディレクトリの集合。


    • ひとつのワークスペースに対して複数のディレクトリ(ワークスペースルート)を登録できる。(Multiroot workspace)

    • ワークスペースルートの配下でないファイルも開くことができる。



  • 汎用の設定とは別にワークスペースごとの設定を行うことができる。

  • ファイルとして保存できる。


    • マルチルートワークスペースを開くと、C:\Users\<ユーザー名>\AppData\Roaming\Code\Workspaces以下にworkspace.jsonファイルが生成されるが、ワークスペースを閉じると削除される。

    • 「ファイル>名前を付けてワークスペースを保存」から、*.code-workspaceファイルとして保存できる。



  • 1ウィンドウ1ワークスペース


Visual Studio Codeのコマンドライン引数

通常は以下のようになる。

"C:\Program Files\Microsoft VS Code\Code.exe" <パス>

ディレクトリパスを渡した場合、ディレクトリをワークスペースとして開く。

つまり、「統合シェルのカレントディレクトリ」を「Codeエディタでワークスペースとして」開きたい、といった場合、bashならcode "$PWD"とかすれば開いてくれる。

そして、引数を複数取ることもできる。

引数にディレクトリパスが含まれる場合、それをワークスペースルートとして開く。

引数にディレクトリパスとファイルパスが両方含まれる場合、ディレクトリパスをルートとしたワークスペースでそのファイルを開く。

"C:\Program Files\Microsoft VS Code\Code.exe" <ディレクトリパス> <ファイルパス>

とかね。


関連付けの変更

今回は、拡張子「.ini」のファイルに対して行った。


Windows関連付けの構造

ともすると拡張子にアプリを関連付けていると考えがちだが、実際には違う。

まず、「拡張子」に「ファイルタイプ」の名前が結びついている。例えば、拡張子「.ini」のファイルは「inifile」というファイルタイプである、というように。

そして、「ファイルタイプ」ごとに、「エクスプローラでダブルクリック(開く)される」などのイベントに応じた「コマンド」が結びついている。「inifile」は「Visual Studio Codeで開く」というように。ただし、このコマンドは、必ずしもアプリで開くというものばかりではない。

今回の場合、「.ini」拡張子のファイルを「inifile」(じゃなくてもなんでもいいけど)というファイルタイプであると定義し、「inifile」を開くイベントに対して、「Visual Studio Codeでよしなに開く」コマンドを定義すればよい、ということになる。


出鼻をくじかれる

実は、最初ポチエス(名称による関連付け専用版)でなんとかしようとしていた。

そのため、エクスプローラの右クリックメニュー→「規定のプログラムを選択」から、iniファイルにポチエス名称(略)=EsExt_c.exeを関連付けしてあった。実際、ダブルクリックしたらEsExt_cが起動する状態だった。

が、後述のftypeコマンドや、レジストリエディタで確認してみたところ、明らかにメモ帳が関連付けされており、メモ帳を別のアプリに変更したところで、なんら動作に変化がなかった。

ポチエスでやる分には問題ないが、きもちわるい。


規定の関連付け情報の削除

ムッカついたので、とりあえず関係するレジストリ情報をぶっ殺した。

レジストリの検索には、以下のアプリを利用した。

色々レジストリを検索してみたところ、削除すべきは以下の3点。



  1. HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.ini


    • 「拡張子のファイルタイプへの関連付け」に該当。

    • 現在は「inifile」。




  2. HKEY_LOCAL_MACHINE\SOFTWARE\Classes\inifile


    • 「ファイルタイプのコマンドへの関連付け」に該当。

    • 現在は「%SystemRoot%\SysWow64\NOTEPAD.EXE "%1"




  3. HKEY_USERS\<なんかのID>\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ini\UserChoice


    • なんかようわからんが、規定のプログラムを選択した時に登録されたやつっぽい。

    • 現在は、「Applications/EsExt.ini "%1"



いちおうレジストリのエクスポートをして、上記3箇所を、(値を空にするのではなく)キーごとバサッと削除した。したらば、iniファイルの関連付けが白紙に戻った。

つまり、エクスプローラで表示されるファイルアイコンが空白になり、ダブルクリックした際にプログラムの選択を求められた。

あとは、通常通り関連付けを行えばよい。


assoc/ftypeコマンドによる関連付け

assoc(iation)が拡張子の関連付けを行うコマンド、f(ile)typeがファイルタイプごとの規定の動作を定義するコマンド。わかりやすい。

とりあえず、assocでファイルタイプを定義するところまではいい。

> assoc .ini=inifile

.ini=inifile

問題は、ftypeでどのようなコマンドを指定するかだ。


引数の展開

今回の場合、Visual Studio Codeには第2引数までを与えるが、ftypeで定義されるコマンドにはファイルパス1つだけしか与えられない。ファイルをダブルクリックするだけだから。

つまり、ファイルパスから親ディレクトリパスを求める必要がある。

で、2つ方法が見つかった。


  1. 「%」 - DOS コマンド一覧 - Programming Field

  2. Windows レジストリ 解剖記: HKEY_CLASSES_ROOT - Programming Field

それぞれ、以下のようになる。

①チルダ(~)記号による引数展開を利用する場合。

ftype inifile="C:\Program Files\Microsoft VS Code\Code.exe" "%~dp1" "%1"

"%V"および%W変数を利用する場合。

ftype inifile="C:\Program Files\Microsoft VS Code\Code.exe" "%W" "%V"

結論から言うと、正解は②

①の方法でも、ファイルのフルパスから親ディレクトリのパスを得ること自体はできる。が、スペースを含むファイルパスに対して、ダブルクォートで囲む際に問題が生じる。

%~dp1%1のどちらもスペースを含む可能性があるので、どちらもダブルクォートで囲む必要がある。囲まないと、スペースが含まれる場合にフツーにわやくちゃになる。

が、両方をダブルクォートで囲った場合、2つの引数「"%~dp1" "%1"」が全体として1つの引数とみなされ、その両端のダブルクォートを削除した上でVisual Studio Codeに渡される。

例えば、「"C:\Program Files\hoge\fuga.ini"」というファイルを開いたとすると、「C:\Program Files\hoge\" "C:\Program Files\hoge\fuga.ini」という、真ん中あたりにへんなダブルクォートの入った1つの引数として渡される。

これが②の方法の場合、%V変数は引数として渡されたファイルのフルパス、%W変数はその親ディレクトリのフルパスとして、よしなに処理される。

いや、本当言うと、色々試したら%W変数が親の親ディレクトリになることがあったりもしたんだが、まあ概ね問題はない。なにも開けない、ということはなかった。

ちなみに、以下の方法で検証済み。開くファイルのパスは「C:\Program Files\hoge\fuga.ini」だとする。


  1. エクスプローラでC:\Program Files\hoge\fuga.iniをダブルクリック


  2. または右クリックメニューから「開く(O)」を選択

  3. fenrirから検索して開く(コマンドはShellExecute|"%P"

  4. コマンドプロンプトでC:\Program Files\hoge\fuga.iniを実行

fenrirの作業ディレクトリはC:\apps\fenrirだし、コマンドプロンプトの作業ディレクトリはC:\User\<ユーザー名>だったし、そもそもVisual Studio Code自体の作業ディレクトリはC:\Program Files\Microsoft VS Codeなのだが、大丈夫だった。

(ややこしいが、Visual Studio Codeにとって、「ワークスペース」と「作業ディレクトリ」は全く違う。あと、Visual Studio Codeの作業ディレクトリと、統合シェルの作業ディレクトリも違う。)

%W=W(oriking Directory)なんていう変数名がついているが、どう考えても親ディレクトリ以外の何者でもない。会社ではパパと呼んではいけませんといっても、コネ入社なのは変わらないだろう。おじいちゃん会長のコネかもしれないが。


まとめ

関連付けするときは%W変数使うと親ディレクトリがとれるよ

      ハ_ハ

とれるよ! ((゚∀゚∩
       \ 〈
        ヽヽ)