[DFって何?][日記][コマンド一覧][関連リンク][予定表][他のファイラー][逃げ帰る]
Windowsで動作するFDのようなものがほしかったので作成開始。
といっても、FDそのものにはちょっち不満な点もあるのでその辺はてきとーに改良というかわたしごのみにすることに決定。
特にExplorerやFDでファイルのコピーなどを行うときのコピー先の指定が煩雑なんで、これをどうにかしたかったのと、FDでファイルを探すときには結局目で探さなくてはならないのが不便なので。まあ、FDにインクリメンタルサーチがあると楽なんですが、コマンド実行と混乱するからしかたないかも。
とりあえずVZのファイラーを参考にして
という機能をつける予定でGo!
WZのファイラーのようにウインドウが必ずくっついている、というのはつまらないので独立したウインドウにする予定。というのも横ではなくて縦に配置したい時もあるし、じゃまな時に片方どけるとか、そういうことができるといいかな、と。
せっかくWindowsなんだし。
とにかく、キーボードで使うことを考えて、マウスで使うことなんかプログラムサイズより優先順位が低いので、多分考えない。
DOS窓のFDで何が気に入らないって、時々DOS窓が不安定になるので使えないわけ。これは別にFDのせいじゃないけど。DOS窓がおかしくなると再起動するまでまともにならないのでうっとうしいんだ。Windowsアプリならコケても何ともないみたいなので。
ディレクトリのコピーもできないし、まだたいしたことはできないけどDOS窓使用のFDよりは快適。
ウインドウハンドルなどをグローバル変数として管理していたので、これらを分離するところで手間取る。
C++で書けばよかった…。
キーアサインはW。
サブウインドウが表示されているかどうかで処理を分岐させている。
機能として用意したのは
の4つなんだけど、とりあえず実装したのはファイル名順と日付順とサイズ順の3つのみ。これは拡張子の判定をどうするかで決めることができなかったため。htmlとHTMは同一視するべきかどうか、拡張子がないファイルはどうするか、など。
キーアサインはS。
ちなみに、この日の時点で実装していたのは、
この時はまだディレクトリは選択できないようにしていた。
今ある機能が安定するように修正。
何かあったような気がするんだけど思い出せない…(^^;)。
理由は↓
ディレクトリまるごと削除機能のテスト中、魔が差して「これ、消せるのかな」と思い、実験。
ターゲットは「.」と「..」。
まずは「.」だけど、さすがにカレントディレクトリは削除できないみたい。ERROR_ACCESS_DENIEDが返ってきたし。
次は親ディレクトリ。これもERROR_ACCESS_DENIEDが返ってくるのではないかと思って気軽に実行。
ああっ、どんどん消してく〜(^^;)。
この時点でバックアップになかったソースは全滅(爆)なので、履歴がわからなくなってしまった(^^;)。
少なくともこの時点で
が実装されていた。
使用コンパイラをSymantec C++7.21JからBorland C++5.01Jに変更。深い意味はない。単にBKEYのmakefileを使いまわしただけだったりする。
エラー処理が実行されないという現象に見舞われ、困る。イヤ、マジで。
何かっていうと、WNetAddConnection2()が常に0を返してくるという現象に惑わされていたわけだ。
実はデバッガの表示が追いついていなかったらしい。
デバッグに協力していただいた<セルダン>氏に感謝。
実は、ドキュメントの誤読が原因とか言う。
登録コマンドダイアログに、選択しているファイルの拡張子に応じてコマンドを変化させるルーチンを実装。
拡張子ごとのコマンドを追加したときに埋め込んだもの。なぜかSymantec C++7.21Jだと動作していたのが不思議。
操作メニューの下がみょーに長くなってしまったので、「操作」「選択」という項目を作りカスケードさせた。すっきり。
ただ、操作の下に「複写」「削除」「改名」「移動」「属性」と長々と続くのが何とも。
対応というほどでもないんだけど。単に圧縮と展開を行えるようにしただけ。
Symantec C++7.21Jで実装し、あとでBorland C++5.02Jでコンパイルしたところ動かなくなってしまい、とんでもなく悩む。
正しくはこう。
; ret=fnUnlha(hWnd, cmd, NULL, 0);
;
@717:
push 0
push 0
lea edx,dword ptr [ebp-1312]
push edx
push dword ptr [ebp+8]
call dword ptr [ebp-28]
なるはずが、こう。
; ret=fnUnlha(hWnd, cmd, NULL, 0);
;
@717:
push 0
lea edx,dword ptr [ebp-1320]
xor ecx,ecx
mov eax,dword ptr [ebp-4]
call dword ptr [ebp-36]
これが問題のアセンブルコード。
__fastcallやんけー。
実は関数ポインタの宣言を血迷って
int (*WINAPI fnUnlha)(const HWND, LPCSTR, LPSTR, const DWORD);
なんて書いてあったのが敗因。 * の位置に注目。
これで2時間くらいハマってしまいました。たかが2時間という感覚かもしれませんが、一日で作業に割り当てられるのがこのくらいなので…(^^;)。
呼び出し形式のデフォルトをSymantec C++では__stdcall、Borland C++のときは__fastcallにしていたために発覚したバグ。どちらも__stdcallにしてあれば一生気づかなかったかもしれない。
アセンブルコードを読めば一瞬でわかるものをなぜかこの日に限って「ドキュメントの見落としに違いない」と思い込んでいた。
WNetAddConnection2()の一件が後を引いていたのだと思われる。
「操作」→「操作」の下に追加。
「複写」「削除」「改名」「移動」「属性」(区切り)「圧縮」「展開」と続く。長い。
あると便利かなーって。
「操作」→「操作」の下に追加。
「複写」「削除」「改名」「移動」「属性」「文字」(区切り)「圧縮」「展開」と続く。長い。
ShellExecute()に変更。これまではCreateProcess()を使用して起動していた。このため、commandと入力するとcommand.exeを起動しようとしてエラーになっていた。
今回、Explorerの「ファイル名を指定して実行」とほぼ同等の動作をするように変更してみた。
ただ、パイプは機能していない。command.comに渡さないとダメなんだろうけど、面倒だしぃ。
書いただけ。
書き足りない部分を追加し、F1を押すと表示するようにした。
ついでにメニューに「?」というのを追加。
バージョン情報ダイアログも追加。
とりあえず勝手に親ディレクトリに登るようにした。
まだカレントドライブがなくなってしまった時の処理は書いてない(^^;)。
というか、LFN非対応に対応。
コピー先ドライブなどがLFNに対応していない時、SFNを使用してコピーするようにした。
NetWareなんて…。
終了時にヘルプを閉じるようにした。
^H ^M も使用できるようにした。ともにBackSpaceとEnterと同義。
8192個のファイルまでしか表示していなかったのを、理論上制限を取り外した。
今までは管理用のメモリを固定長の配列で管理していたため、8192個以上のファイルがあった時には切り捨てていた。ちなみに1つのウインドウあたり2.4MBものメモリを使用していた(^^;)。
今回、可変にしたため、30個までなら4KBで済む計算になる。
ファイルの数が多いとメモリブロックの確保と開放を繰り返すのでオーバヘッドが大きくなるかもしれない。と思っていたらLibretto SSではかなり重く感じてしまったので16KBごととるようにする。でも重い。
ファイルサイズも大きくなったし全然いいことなし。
なんでだ〜。
ちなみにWinFDよりはずっと高速。何もしてないからねー(^^;)。
また、これも別ウインドウ開いて処理するパターン。このままぱたぱたウインドウ開きまくる感じで処理してナデシコなふぁいらーになるとおもしーかも。
コピー中には「複写中」とか、そういう感じで動作中にはその旨表示するようにした。
複数のファイルを処理する時に処理対象のファイルを表示するウインドウを、メインウインドウとずらして表示するようにした。
と、ウインドウが背後に回り込んだり信じられないほど乱れたりしたのでちょっち対策。
何のことはない、バックグラウンドにいる時には表示しないようにしただけのことだったりして。世の中なかなかむつかしい。
ディレクトリをサブディレクトリにコピーすると案の定無限ループに陥るのでエラーにするようにした。
先頭に移動、最後に移動、ということでこれらのショートカットキーを追加。
Explorerのプロパティで表示されるアレ。
絶対ボールドで表示していたが、INIファイルの設定で切り替えられるようにした
ディレクトリ名を[]でくくって表示できるようにした。INIファイルで切り替える。
選択状態を、反転表示だけではなくて、マークをつけるようにした
VirtualAlloc()を使用していたのをHeapAlloc()に変更。こちらの環境ではHeapAlloc()の方が体感できるほど高速だったため。
ただし、バージョン情報取得の部分はまだVirtualAlloc()を使用している。深い理由は無く、まだ修正に着手していないだけだったりする。
後ろに回り込んでしまう理由がわかったため、対策を講じる。コレで処理中ウインドウを節操無く表示できるようになった。
理由は、
というわけで、ウインドウをアクティブにしないようにするとうまくいった。
ディレクトリが見つからないとき、親ディレクトリに移動するようにしてあったが、ここでのルートディレクトリかどうかの判定にバグがあったため、UNCパス(\\machine\share\とかいうやつ)に移動できないことがあった。なぜか移動できることもあった…というかおおむね移動できていたのでよく解らなかったのだ。
大量にコピーしているとウインドウが結構アレなので、表示だけは行うようにした。このため作業中に「応答なし」にならなくなった。
いつ発生するかわからないので悩む。
デバッグしようとして、Symantec C++でコンパイルすると再現しない。
かっこつけたディレクトリ表示を行っていた時に、文字列長を判断しそこなっていたのを修正。
再現させる方法がわかった。
しかし原因を追及しようとして、Symantec C++でコンパイルすると再現しない。
アセンブルコードを読んで原因判明。メインウインドウを破棄するときにサブウインドウが存在しているときには先にサブウインドウを破棄する、というコーディングをしていたんだけど、今処理しているウインドウはどちらなのか、を保持しているフラグが最適化によってレジスタに割り当てられていた。破棄する関数がサブウインドウを破棄するために再帰呼出しするためにこのレジスタが破壊され、サブウインドウの管理用メモリを開放した後にもう一度同じメモリを開放しようとしていたため。
窓破棄(ウインドウ wnd){
x=wndはメインウインドウか?
if(x){
if(まだサブウインドウがあるなら){
窓破棄(サブウインドウ);
/* ここでxが0に、つまりサブウインドウ処理中を示す値になっている */
}
}
/* そのためここですでに開放したはずのサブウインドウのメモリを再度開放しようとする */
メモリ開放(x);
}
奥が深いバグであった。
キーを押すだけで今起動しているDFをアクティブにする機能を追加。
呼ばれて飛び出てじゃじゃじゃじゃ〜んな感じ。
Windows 98ではSetForegroundWindow()が使えないらしいので、ちょっちコスイ手を使っていたりするけど動作未確認(笑)。
誰か試して(^^;)。