ID:???前に雑記を書いていたサイトが完全に消滅してしまったので、AutoHotkey関連の記事をこちらに再掲載することにする。内容は当時のままなので、現在のAutoHotkeyとは異なっている場合があるかも。EditionでAutoHotkeyをビルドするスクリプトが肥大化してきたら気まぐれで発生するようになった謎のエラーを何とかしたい。エラー内容を見ると、「0x0000000f」というアドレスを参照しているらしい。0x00000000ではないということは、構造体へのポインタがnullの時にメンバを参照しようとしているのだろう。そんなわけで、ソースコードから問題の箇所を探そうとしたが、やたらと長大で挫折した。デバッグ実行でエラーを発生させて問題の箇所を見つけてみることに。VC7向けに作られているらしく、手持ちのVC6.0ではコンパイルできなかったので、無償提供されているVC2005EEを使うことに。XPのSP2にしかインストールできないということで、サブマシンにインストールする。DaemonToolsで配布isoイメージをマウントしてインストールを行い、AutoHotkeyのプロジェクトをインポートしてみたが、windows.hがないとか言われてビルドできない。PlatformSDKがインストールされなかったらしい。一緒に使う(http://www.microsoft.com/japan/msdn/vstudio/express/visualc/usingpsdk/)というページに従ってインストールする。合わせて50分くらいかかった。ビルドを試みると、死ぬほど警告が表示された。プロジェクトの設定で警告を切ると、いくつかのエラーが残った。suffix」という宣言が利いていない問題は、言語の拡張設定で直った。char*をchar*に変換できないというエラーは、よく分からないので引数からconstを削除して黙らせた。宣言の型が指定されていない部分がいくつかあったが、適当にintと書き足したら大人しくなった。コンパイルは成功するようになったが、リンク時にリソースが重複しているとか言われてビルド完了できない。設定で埋め込みマニフェストを無効にしたら、とりあえず回避できた。そんなわけで、とりあえずビルドできたので、問題のあるスクリプトを実行させてデバッグしてみる。GUIウィンドウが表示されてエラーが発生すると、実行中だった箇所や関数の呼び出し元、変数の内容などの情報が表示された。思った通り、nullなオブジェクトの関数を呼び出している部分があった。関数のローカル変数の情報を格納するオブジェクトのアドレスを格納する部分が、不正にnullになっているらしい。通常は正しいアドレスが格納されていたので、どこかで上書きされてしまっているのだろう。いつnullになってしまうのか調べるため、ブレークポイントを仕掛けてそのアドレスの変更を監視したところ、strlcpy関数で文字列のコピーを行っているときに上書きされてしまっているらしいことが分かった。問題の箇所はscript.cppの以下の部分。//!!!!!!!!!!!!!!!!!aBufの指すアドレスにMAX_PATHを足すと、ちょうどnullになってしまった領域をまたいでいる。aBufとして確保されている領域のサイズを考慮せずにMAX_PATH文字をコピーしてしまっているのが原因らしい。呼び出し元を追跡すると、その変数の領域は64バイトしか確保されていないらしかった。strlcpyが元の文字列の終端以降もコピーを行うのは妙な気がするが、Wikipediaの説明には指定されたサイズを超えないとしか書かれていないので、サイズ分丸ごとコピーされても文句は言えない。思ったら、よく見たらutil.hの中で自前で定義されていて、strncpyに丸投げされていた。VCのstrncpyの説明にはコピー元の文字列が短かった場合は残りの部分を\0で埋めると書いてあったので、正しい動作らしい。そんなわけで、原因はおおよそ特定できたが、改善策を考えるのが面倒なのであきらめた。作者が適当に修正してくれることを祈る。スクリプトの方は、適当にダミーの関数を追加したらとりあえず動くようになった。いつ駄目になるか分からないので困る。■AutoHotkey(http://www.autohotkey.com/)1.0.42.06がんばって英文を書いて公式のバグレポートに報告したところ、strncpyのバグが修正されたようで、問題のあったスクリプトが正常動作するようになった。■fenrir風の奴を修正049.zip(http://lukewarm.s101.xrea.com/up/file/049.zip)AutoHotkeyのバグが修正されて、エラーを気にせずに機能拡張できるようになったので、いくつか気になっていたところを改良した。・上下キーでの移動の際、リストの上下をループするように10個くらい候補があるときに下の方の項目を素早く選択したくなったので、一番上で↑キーを押したら一番下に行くようにした。「/a」コマンドで日本語のタイトルを付けようと思ったら失敗したので気づいた。ImmGetCompositionStringで変換中の文字列があったら、確定を行わないようにした。・存在しないファイルを選択したとき、即座にインデックスから削除するようにしたついでだから、上位フォルダのパスをチェックして、存在しない最上位階層からまとめて削除するようにした。・「-」を付けると除外検索になるようにノイズをまとめて消せるようにしたい。1文字打つごとに前回の結果から絞り込む現在の方式では、「-t」と打った時点でtを含む全ての項目が消されてしまい、「-tx」になっても「tx」を含まずに「t」を含む項目が消えたままになってしまう。除外検索があるときだけ、全候補から全キーワードで絞り込むようにすることも考えたが、打つたびに候補が増えていくというのは気にくわないのでやめた。」のようにスペースを打った時点で前の除外ワードによる絞り込みが行われるようにした。「/scan」とか「-dict」のように特殊なキーワードと解釈されてしまう場合に「+/scan」「+-dict」のようにすることで検索できるようにした。■タスクトレイアイコンをキーボードで操作するAutoHotkeyスクリプトTrayIconList.zip(http://lukewarm.s101.xrea.com/myscripts/TrayIconList.zip)ノートPCで使うために作った。プロセス名とツールチップテキストをリスト表示し、キー操作に応じてダブルクリックや右クリックなどの動作を行うように。左手だけで操作できるように、Tab/Shift+Tabにカーソル移動を、Ctrl+S/D/Rに各クリック操作を割り当てた。当初は、修飾キー無しのアルファベットキー単独で操作できるようにしようかと思ったが、リストビューの方でインクリメンタルサーチが提供されていることに気づいたので、そっちを生かすことに。一部のソフトでメニューにフォーカスが当たらなくて悩んだが、メニューの親ウィンドウにフォーカスをやればアクティブになるようだった。非常駐でできるだけ高速化することに。トレイアイコン情報取得は、このあいだ作ったモジュールを使わず、無駄な処理を省くようにした。タスクトレイアイコン操作(http://lukewarm.s101.xrea.com/myscripts/TaskTrayIcon.zip)のモジュールの方は、ツールチップテキストを取得する関数を追加した。■AutoHotkeyシステムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)作った。当初、RegQueryValueExでHKEY_PERFORMANCE_DATAから構造体を取得するという面倒くさそうな話を聞いていたが、PDH.DLLという物のAPIで簡略化できるらしい。サンプルを移植して動かしてみたが、システム全体のCPU使用率が取得できないし、なぜかカウンターを登録するときに以上に時間がかかるし、特定のプロセスIDの状態を監視するのも面倒くさそうで気に入らない。その後、GetSystemTimes、GetProcessTimes、GlobalMemoryStatus、GetProcessMemoryInfo等を使えば普通に取得できることが分かる。適当に作った関数でも、十分な速度で動作している模様。PDH.DLLの存在意義が疑われる。■AutoHotkey用システムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)更新PDH.DLLのAPIでは様々な情報が取得できるが、.Netの奴の何かなど、訳の分からないものやどうでもいい物が大半だった。ディスクのアクセス量なども取得できるらしいので、とりあえず関数を作ってみることに。取得したい情報はパス文字列で指定しなければならない。PdhBrowseCountersというAPIで項目を選択するダイアログが出せるとのことなので、それを呼び出す関数を作成した。ディスクのアクセス率を取得してみると、それらしい物が取得できた。アクセス率とアイドル率を足して100にならないなど怪しいところはあるが、気にしないことにする。次に、ネットワークの使用率を取得してみる。パス文字列にはネットワークインターフェイスの名前が含まれる。interface」というのと、PCに接続されたNICらしき物の2つがある。実際に必要なのはNICの方だが、PCによって違うので、何らかの方法で取得しなければならない。PDHのAPIで自動取得できるようにするのは面倒だったので、以下のような方法で取得取得してもらうことにした。%tmp%\route.txt,,HIDEFileReadLine,nic,%tmp%\route.txt,4StringTrimLeft,nic,nic,32FileDelete,%tmp%\route.txtとりあえずパス文字列ができたのでモニタリングしてみたが、なぜか値がおかしい。テストダウンロードを行っているIrvineの示している転送量の70%くらいの値になってしまう。Windowsの管理ツールにあるパフォーマンスモニタで監視しても同じなので仕様だろう。TClockのソースを見たら、ネットワーク転送量はiphlpapi.dllというDLLの関数で取得していることが分かったので、せっかくだから移植してみることに。データを受け取るのに必要なバッファが10KBくらいあって気持ち悪い。構造体の定義もややこしく、メンバのアドレスオフセットを計算するのが面倒なんで、VCで適当に「printf("%d\n",(int)(&(st.dwInOctets))-(int)(&st));」のようなコードを書いて実行して調べた。その他は、他のモニタリング関数と同じような感じで適当に作ったら動いた。サンプルスクリプトも作ることにした。ラベルとプログレスバーで情報を表示し、背景を透過して文字だけが浮かんでいる状態にし、最前面に表示するようにした。取得できる情報を片っ端から表示することに。HDDの情報は、ドライブの数だけ列挙する。ついでに、DriveSpaceFree命令などを利用してHDDの空き容量も表示できるようにした。フォントなどを工夫したら、それなりに見栄えのするシステムモニタができた。ドライブが7つもあると無闇に縦長になってしまって邪魔だが。スクリプトのメモリ使用量が15MBを超えていて、あまり実用性はない。■AutoHotkey製コマンドラインランチャーの奴を更新FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)飽きてきたので正式版っぽい感じにしてスクリプト公開ページに載せた。追加せっかくBREGEXP.DLLを使っているので、任意の正規表現で検索できるようにした。or検索とか、任意の数字列を含むファイルを検索とか、たまに役立つかもしれない。タイプの途中でマッチングが行われると困るので、除外検索の時と同じように後ろにスペースを打つまでは検索されないようにした。・ファイルの名前部分のみから検索する機能を追加AutoHotkey.exeを実行したいのにAutoHotkeyフォルダ内の全てのファイルが列挙されたりすると鬱陶しいので付けてみた。パスを区切るのが面倒なんで、正規表現を生成して検索するように。・デフォルトの検索モードを変数で指定するようにMigemoを頻繁に使う時でもいちいち「:」を付けるのは面倒なので、デフォルトの検索モードを変更できるようにした。SMode=:」のようなコマンドでも変更できる。「@rm」で「readme.txt」を検索するなど、短縮ワードによる検索を可能にした。正規表現検索モードなども割り当てられるので、「@ahk」で「AutoHotkey」か「.ahk」を含むアイテムを検索すると言ったことも可能。検索モード指定文字は打ちやすいようにShiftと組み合わせないキーにしたかったが、ファイル名に使われない文字ではMigemoに割り当てている「:」しか無かったので、あまり使われなさそうで打ちやすい位置にある「@」を割り当てることにした。■AutoHotkey製コマンドラインランチャーの奴を更新FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)・ドラッグ&ドロップでファイルを追加できるようにマウス操作はあまり必要ないだろうが、一応付けた。・起動時や多重起動時に任意の動作を実行させる機能を追加スクリプト中で番号にコマンドやサブルーチンを割り当てておいて、ウィンドウメッセージで実行させるように。メッセージを送るウィンドウを検出するのが面倒だったので、スクリプト起動時にIniファイルに書き込んでおくようにした。スクリプト以外のプログラムからも任意のコマンドを実行させられるように、Iniファイル経由でコマンドを指定する機能も付けた。上記の機能で使用するための物や、スキャンリストにフォルダを追加する物など、いくつか追加した。拡張子ごとにファイルを開くプログラムを振り分けるようなコマンドを定義できるようにしようかと思ったが、面倒なんで内部コマンドとして記述してもらうことにした。簡単な記述で実現できるので、わざわざ定義ファイルによる割り当て機能を付ける必要はないだろう。定期的にスキャンなどを実行させる機能も、設定ファイルなどを用意するのは面倒なので、スクリプト中にSetTimer命令などで記述するようにした。そんなわけで、今度こそ実現したかった機能は一通り作り終わった。何も思いつかなかったら正式版ということにしよう。いつの間にか配布ZIPファイルのサイズで21KBにもなってしまっていた。■AutoHotkey(http://www.autohotkey.com/)1.0.43.00Sendコマンドに2つの別モードが用意されたらしい。「SendInput」コマンドでは、同名のAPIを呼び出して一括して入力内容を流し込むらしい。高速らしいが、キーフックを使用していると利用できないらしく、あまり使い道はなさそう。「SendPlay」では、ウィンドウメッセージのような仕組みで入力内容を送り込むらしい。一部のゲームでは、通常のSendでは操作できないがSendPlayを使うことで操作できるようになるとのことだが、SendでもSendPlayでも操作できないゲームがあった。これらの新しいモードは、従来のモードをSetKeyDelay,-1で使用した場合よりも高速に動作するとのことである。試したところ、確かに多少高速になっていた。一連の操作の間に外部から他の操作が割り込まれて動作がおかしくなるということも避けられるらしい。新たにClickコマンドが追加された。従来のMouseClickでは、コントロールパネルで左右のボタンを入れ替えていると、MouseClickが右クリックの動作に、MouseClick,Rが左クリックの動作になっていたが、Clickコマンドでは入れ替えがあってもなくても同じ動作が行われるらしい。2005-10-08。