(AutoHotkey)(拡張子によって 起動するプログラムを振り分けるアプリケーションを作ってみる 編)

 例えば .mp3ファイルであっても 「プレーヤーで開きたい」 とか 「波形編集ソフトで開きたい」とか
時と場合によって 開くソフトを変更したい場合がありますよね
そういう時 .mp3ファイルをダブルクリックすれば メニュを表示して どのソフトで起動したいかを
選択できるようにしておけば 便利ですよね
ということで そういう ツールを作ってみる事にします


 まず 最初の問題が、 .ahkファイルに対して .mp3を関連付けする事が出来ないということです
よって .ahkファイルを .exeファイル化すれば その問題は 解決するわけですが
.ahkファイルを変更する毎に いちいち コンバートするのは ぶっちゃけ 面倒ですよね?
それを 解決する手段としては いわゆる 「ラッパー.exe」 を 作るのが一番手っ取り早そうです
作ってみた所 こんな感じになりました
ファイル名 は 「ファイルドロップラッパー.ahk」等として保存し
コンバーター(Ahk2Exe.exe)で 「ファイルドロップラッパー.exe」を作成します

使用する時は この後作る スクリプトと 同名の.exeファイルに リネームします
例えば 「abcd.ahk」のラッパーにしたい時は 「abcd.exe」とリネームします

Gosub, ExecuteAhkScript Return ;------------------------------------------------------------------------------------------------------ ExecuteAhkScript: { AhkScript := A_ScriptDir . "\" . E2F(A_ScriptName) . ".ahk" Loop, %0% { If ( A_Index > 1 ) DropedFiles .= " " DropedFiles .= FN2FS(%A_Index%) } RunEx(AhkScript, DropedFiles) Return } Return ;------------------------------------------------------------------------------------------------------ ; 以下は 現在作成中の 自分用のライブラリから必要なものを抜粋したものです ; ;------------------------------------------------------------------------------------------------------ ; E2D(Expression, BufferSize = 1000) ファイル名と思われる文字列から ディレクトリと思われる部分抜き出す ; 最後の「\」は付かない ; 「フルパス」の「ロングファイル名」で渡す必要がある ; 由来:ExpressionToDirectory E2D(Expression, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) Buf := Expression DllCall("shlwapi.dll\PathRemoveFileSpecA", "Str", Buf) Return Buf } ;------------------------------------------------------------------------------------------------------ ; E2F(Expression, BufferSize = 1000) ファイル名と思われる文字列から 拡張子を含まないファイル名と思われる部分を抜き出す ; ファイルの存在はチェックしていない ; 由来:ExpressionToFilename E2F(Expression, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) DllCall("kernel32.dll\lstrcpyA", "Str", Buf, "Int", DllCall("shlwapi.dll\PathFindFileNameA", "Str", Expression) ) DllCall("shlwapi.dll\PathRemoveExtensionA", "Str", Buf) Return Buf } ;------------------------------------------------------------------------------------------------------ ; FN2FL(FileName, BufferSize = 1000) ファイル名 を 「フルパス」の「ロングファイル名」に 変換 ; ファイルが存在しない時は 値無し(="") FN2FL(FileName, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) DllCall("kernel32.dll\GetLongPathNameA", "Str", FileName, "Str", Buf, "UInt", BufferSize) DllCall("kernel32.dll\GetFullPathNameA", "Str", Buf, "UInt", BufferSize, "Str", Buf, "UInt", 0) Return Buf } ;------------------------------------------------------------------------------------------------------ ; FN2FS(FileName, BufferSize = 200) ファイル名 を 「フルパス」の「ショートファイル名」に 変換 ; ファイルが存在しない時は 値無し(="") FN2FS(FileName, BufferSize = 200) { VarSetCapacity(Buf, BufferSize, 0x00) DllCall("kernel32.dll\GetShortPathNameA", "Str", FileName, "Str", Buf, "UInt", BufferSize) DllCall("kernel32.dll\GetFullPathNameA", "Str", Buf, "UInt", BufferSize, "Str", Buf, "UInt", 0) Return Buf } ;------------------------------------------------------------------------------------------------------ ; RunEx(ExecuteFileName, Parameter, WorkDirectory = "", SW_xxxx = 1) Runコマンドの拡張版 ; 引数は順に 「実行したいファイル名」「コマンドライン引数」「作業ディレクトリ(省略可)」「起動時の状態(省略可)」 ; 「実行したいファイル名」 は 間に 半角スペース を含んでいても " で くくる必要は無い、 ショートファイル名でも可 ; 「コマンドライン引数」 は 不必要時でも "" と 明記する必要がある ; 「作業ディレクトリ」 は 省略した時は 「実行したいファイル名」と同じディレクトリが対象になる ; 「起動時の状態」 は 省略した時は 普段 Explorerから ダブルクリックで実行した時と 同じ挙動をする ; SW_xxxx の値に関しては 「通常 = 1」「最小化 = 2」「最大化 = 3」「最小化(非アクティブ) = 7」 など ; その他の動作は SW_で始まる定数を参照のこと RunEx(ExecuteFileName, Parameter, WorkDirectory = "", SW_xxxx = 1) { If ( (ExecuteFileName := FN2FL(ExecuteFileName)) == "" ) Return 0 If ( WorkDirectory == "" ) WorkDirectory := E2D(ExecuteFileName) . "\" Return DllCall("shell32.dll\ShellExecuteA", "UInt", 0 , "Str", "open" , "Str", ExecuteFileName , "Str", Parameter , "Str", WorkDirectory , "UInt", SW_xxxx) }


 ラッパーが出来たので 今度は 本体を作ります
とりあえず 名前は 「FileLaunchManager(FLM)」という事にします

 この手のツールというのは これまでも いろいろと出回っていたかもしれませんが
本ソフトは AutoHotkeyで 作成しているわけなので ある程度の AutoHotkeyのスキルがあれば
個人的に 柔軟なカスタマイズが簡単に出来るというメリットがあります
もちろんですが AutoHotkeyで出来る事は 何でも出来るわけですので
単なる ソフトスイッチャー の 枠を超えたものも 出来るかもしれませんね 笑)

 ということで 作ってみると こんな感じになりました
ファイル名 は FileLaunchManager.ahk
↑で作った ラッパー.exeファイル の 名前を FileLaunchManager.exeにリネームして
同じフォルダに入れておいてください
各ファイルの 関連付けは FileLaunchManager.exe に対して行う事になります


;------------------------------------------------------------------------------------------------------ ; 初期化処理 Gosub, Init Gosub, ShowMenu Return Init: { ; ドロップされたファイル名を取得 SetEnv, InputFileName, %1% ; ドロップされたファイル名の拡張子を取得 InputExt := E2E(FN2FL(InputFileName)) ; 変数内の 大文字を 小文字に変更してしまう ; 「実ファイル」の拡張子が 大文字であっても ここで 小文字になる CharLower(InputExt) Return } ;------------------------------------------------------------------------------------------------------ ; メニューの構築 と 表示 ShowMenu: { ; 拡張子 は InputExt に格納されています ; 最初の「.」も含んでいます ; 全て 小文字に置換されていますので 大文字で比較する必要はありません Menu, ExecuteMenu, Add, 何もしない, _NoOperation ; foobar2000 で 開く If ( RegExMatch(InputExt, ".cue|.m3u|.wav|.mp3|.wma|.asf|.tta|.ape|.flac|.tak") ) { Menu, ExecuteMenu, Add Menu, ExecuteMenu, Add, foobar2000 で 開く, _foobar2000 } ; Leeyes で 開く If ( RegExMatch(InputExt, ".jpg|.jpeg|.bmp|.png|.gif|.rar|.zip") ) { Menu, ExecuteMenu, Add Menu, ExecuteMenu, Add, Leeyes で 開く, _Leeyes } ; MediaPlayerClassic で 開く If ( RegExMatch(InputExt, ".wav|.avi|.mpg|.wmv|.mp4|.vob|.ifo|.mkv|.flv|.swf|.wma|.mp3") ) { Menu, ExecuteMenu, Add Menu, ExecuteMenu, Add, MediaPlayerClassic で 開く, _MPC } ; DaemonToolsにマウント If ( RegExMatch(InputExt, ".iso|.cue|.mds") ) { Menu, DaemonToolsMenu, Add, デバイス0 に マウント, _DaemonTools0 Menu, DaemonToolsMenu, Add, デバイス1 に マウント, _DaemonTools1 Menu, DaemonToolsMenu, Add, デバイス2 に マウント, _DaemonTools2 Menu, DaemonToolsMenu, Add, デバイス3 に マウント, _DaemonTools3 Menu, ExecuteMenu, Add Menu, ExecuteMenu, Add, DaemonTools の, :DaemonToolsMenu } Menu, ExecuteMenu, Show Return } ;------------------------------------------------------------------------------------------------------ ; メニューから呼び出される処理 ; ドロップされたファイル名 は InputFileName に 格納されています、形式は「フルパスのショートファイル名」です ; もし ロングファイル名が必要な場合は FN2FL(InputFileName)とすれば 「フルパスのロングファイル名」 に 変換できます ; その場合 「"」でくくるような表記をしないと、 半角スペースを含むファイル名の場合思ったような動作をしませんので注意してください ; RunEx() の仕様は ↓の関数定義の所を参照してください _NoOperation: { Return } _DaemonTools0: { RunEx("c:\Program Files\DAEMON Tools Lite\daemon.exe", "-mount 0`," . InputFileName) Return } _DaemonTools1: { RunEx("c:\Program Files\DAEMON Tools Lite\daemon.exe", "-mount 1`," . InputFileName) Return } _DaemonTools2: { RunEx("c:\Program Files\DAEMON Tools Lite\daemon.exe", "-mount 2`," . InputFileName) Return } _DaemonTools3: { RunEx("c:\Program Files\DAEMON Tools Lite\daemon.exe", "-mount 3`," . InputFileName) Return } _foobar2000: { RunEx("c:\Program Files\foobar2000\foobar2000.exe", InputFileName) Return } _Leeyes: { RunEx("d:\Tool\Leeyes\Leeyes.exe", InputFileName) Return } _MPC: { RunEx("d:\Tool\MediaPlayerClassic\mplayerc.exe", InputFileName) Return } ;------------------------------------------------------------------------------------------------------ ;------------------------------------------------------------------------------------------------------ ; 以下は 現在作成中の 自分用のライブラリから必要なものを抜粋したものです ; ;------------------------------------------------------------------------------------------------------ ; CharLower(ByRef Expression) 文字列変数内 の 大文字を 小文字に 置き換えてしまう、 2バイト文字も可能 ; 戻り値 は 指定した文字列のアドレス CharLower(ByRef Expression) { Return DllCall("user32.dll\CharLowerA", "Str", Expression, "UInt") } ;------------------------------------------------------------------------------------------------------ ; E2D(Expression, BufferSize = 1000) ファイル名と思われる文字列から ディレクトリと思われる部分抜き出す ; 最後の「\」は付かない ; 「フルパス」の「ロングファイル名」で渡す必要がある ; 由来:ExpressionToDirectory E2D(Expression, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) Buf := Expression DllCall("shlwapi.dll\PathRemoveFileSpecA", "Str", Buf) Return Buf } ;------------------------------------------------------------------------------------------------------ ; E2E(Expression, BufferSize = 1000) ファイル名と思われる文字列から 拡張子と思われる部分だけを抜き出す ; 最初に「.」が付く ; 「ロングファイル名」で渡す必要がある ; ファイルの存在はチェックしていない ; 由来:ExpressionToExtension E2E(Expression, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) DllCall("kernel32.dll\lstrcpyA", "Str", Buf, "UInt", DllCall("shlwapi.dll\PathFindExtensionA", "Str", Expression)) Return Buf } ;------------------------------------------------------------------------------------------------------ ; FN2FL(FileName, BufferSize = 1000) ファイル名 を 「フルパス」の「ロングファイル名」に 変換 ; ファイルが存在しない時は 値無し(="") FN2FL(FileName, BufferSize = 1000) { VarSetCapacity(Buf, BufferSize, 0x00) DllCall("kernel32.dll\GetLongPathNameA", "Str", FileName, "Str", Buf, "UInt", BufferSize) DllCall("kernel32.dll\GetFullPathNameA", "Str", Buf, "UInt", BufferSize, "Str", Buf, "UInt", 0) Return Buf } ;------------------------------------------------------------------------------------------------------ ; RunEx(ExecuteFileName, Parameter, WorkDirectory = "", SW_xxxx = 1) Runコマンドの拡張版 ; 引数は順に 「実行したいファイル名」「コマンドライン引数」「作業ディレクトリ(省略可)」「起動時の状態(省略可)」 ; 「実行したいファイル名」 は ロングファイル名 で 間に 半角スペース を含んでいても そのままで大丈夫、 ショートファイル名でも可 ; 「コマンドライン引数」 は 不必要時でも "" と 明記する必要がある ; 「作業ディレクトリ」 は 省略した時は 「実行したいファイル名」と同じディレクトリが対象になる ; 「起動時の状態」 は 省略した時は 普段 Explorerから ダブルクリックで実行した時と 同じ挙動をする ; SW_xxxx の値に関しては 「通常 = 1」「最小化 = 2」「最大化 = 3」「最小化(非アクティブ) = 7」 など ; その他の動作は SW_で始まる定数を参照のこと RunEx(ExecuteFileName, Parameter, WorkDirectory = "", SW_xxxx = 1) { If ( (ExecuteFileName := FN2FL(ExecuteFileName)) == "" ) Return 0 If ( WorkDirectory == "" ) WorkDirectory := E2D(ExecuteFileName) . "\" Return DllCall("shell32.dll\ShellExecuteA", "UInt", 0 , "Str", "open" , "Str", ExecuteFileName , "Str", Parameter , "Str", WorkDirectory , "UInt", SW_xxxx) }
 上手く動けば
関連付けをした ファイルの拡張子によって 開く事の出来る ソフト一覧が メニューで表示されるようになります
キャンセルしたい時は 「何もしない」を クリックするか
表示されたメニュー以外の 適当な場所をクリックして メニューを閉じてください

 もちろんですが 必要に応じて 自分の環境に合うように FileLaunchManager.ahk を 変更していってくださいね