[DFって何?][日記][コマンド一覧][関連リンク][予定表][他のファイラー][逃げ帰る]
DFのソートを安定したソートに変えようと思ってクイックソートからマージソートに書換える。単純なマージソートだとバッファが必要だげどそんなメモリは無いのでやりくりしてみる。8要素以下のブロックはインサートソートにして速度を稼ぐ。
結果、クイックソートの倍近く遅くなった。んがー。
メモリをやりくりするところが遅いようだ。
memmov()を高速化してみる。ダメ。遅い。クイックソートに戻す。
安定ソートにしておけば、名前でソートした後に更新日付でソートすると、更新日付順で、同じ日付ならば名前順に並ぶので。今までは勝手に上下関係の区別がつかない時は勝手に名前順にしていたという。このため拡張子順でソートする時には拡張子で比較したうえでファイル名でも比較するという感じでかなり無駄だった。
何がしたいって、属性によるソートも実装しようかと思って。まあ、今まで通り属性で比較して判断できなかったら名前順、というのでもいいんだけど。
描画高速化の手を思いつく。
描画時に属性を判定して色を決定しているのだけど、ディレクトリ検索時に判定してその判定結果を保持しておけば、描画時の処理が減る。1ファイルあたり4バイト増える。
このタイミングで判定しておけば、拡張子ごとの色を変える時でも負荷は増えない。ハズだ。
GetPrivateProfileString()の呼び出しを減らすことで実現できると思っていたけど、呼びだし回数を減らすことはできないことが判明。動作を勘違いしていた。ちぇっ。
GetPrivateProfileString()を使わずに一から全部書けば速くなるかもしれないけど、サイズが。
ソートは順位を保持する配列を別に用意して、同時にソートするように作れば解決するか?
現在、拡張子順のソートが極めて遅いのだけど、この辺もデータをキャッシュしてソートするようにしてやれば速くなりそう。
ソートルーチンを書き直すのが面倒というか。この間書き直したばかりなので見たくないというか。
今のソートルーチンは直接配列の要素を交換しているので、引数は交換対象の二つだ。これを別の配列も操作できるようにするとなると、引数を二つ増やさないとダメか。
さあ、どーする。
つーわけで(なにが)案3で実装。
拡張子ごとでのソートが高速になった。
同一順位の場合は、前回の順位でソートする。…が、マズイ。
名前順でソートして拡張子順でソートすると、拡張子順でソートされ、同じ拡張子の場合には名前でソートされる。
この状態でファイルを更新すると読み込みなおす。この時、先程は名前でソートしてから拡張子でソートしたことは忘れているので拡張子でソートする。同じ拡張子の場合はディレクトリエントリから取得した順番でソート。
仕様通りだ。この動作が気に入らない。
ボタンの高さを14pxにする。今までは12pxで足りていたと思っていたのだけど気がついたら文字がはみ出るというかフォーカスを現す破線があると文字に被さっている。
煽りに乗って修正。
[OPT]のCTRLSEARCHに1(0以外の値ならなんでもOk)を設定するとShiftの代わりにCtrlで頭文字検索。
WM_CHARで処理していたのをWM_KEYDOWNに換えたので、キー入れ換えソフトなどを併用していると誤動作する可能性あり。
Shift+1で!から始まるファイルではなくてではなくて1から始まるファイルを検索するという副作用あり。
私自身はCtrl+何かをコマンドに割り当てるほうに馴染んでいる。エディタとか、ふつーはShiftで文字のシフトを切り替えるのでCtrlかAltがコマンド用に割り当たっているわけでShiftをコマンドに割り当てるという文化は想像を絶するものが。
必ずInvalidateRect()を呼び出していたのをやめる。
ファイルサイズ 88,576バイト。
検索モードからのコピーのデフォルト動作はディレクトリを付けないコピーにした。
忘れた。
情報表示ウィンドウと同じフォントを使用する。
ファイルサイズ 89,088バイト。
フォント作ったらダメかよー。
戻すかどうか悩む。
プロポーショナルフォントを使用した時の残念な思いの度合を減らす。
容量表示がタイムスタンプを上書きしなくなったのがわかる。
っていうか、まさかプロポーショナルフォントで使っている人がいるとは思わなかった。
コードが小さくなるように改善するが、あまり効果は無かった。
Alt、Ctrl、Shiftキーの状態を示す謎のフラグと、仮想キーコードを指定するというわからない人には決してわからない指定の仕方。
カスタマイザでフォローできるようにしたい。したいなあ。できたらいいなあ。
[FCOLOR]セクションにファイル名のパターンと、対応する色をRGBで指定する。
[FCOLOR] *.EXE=FFFF00 *.BMP;*.JPG;*.PNG=FF8000
という感じ。
ファイルサイズ 89,600バイト。
うーむ。
ファイルサイズ 89,088バイト。
テキストビューアとか、最近付けた機能を外したらどのくらい小さくなるのだろう。
ファイルサイズ、属性、タイムスタンプの背景色の指定を間違えていた。
Ctrl+なんとかで頭文字検索しようとしたときの副作用。
解決できそうに無いのでCtrlで頭文字検索は外す。
再度実装。
コマンドキーとの兼ね合いはむりやり分岐して回避。
表示する項目が無い時に描画処理をスキップするようにしていたら、領域の初期化すらしなくなっていてゴミが残る状態になっていました。
ソートした時など、再描画する時に領域を初期化するのが抜けていました。
ソートダイアログの初期状態を現在のソート状態にする。
って書くと簡単だけどなかなかうまくいかなくて手間取った。
現在ソートしている状態に応じてボタンのデフォルトボタンにする。それだけのことだ。
というわけでボタンのスタイルを変更する。スタイルを変更するにはetWindowLong()でGWL_STYLEを指定する。
あれ、変わらない。ん? 間違ったかな?
FPROGでチャットしながらだったので、ぐちりながら作業継続。
お、BM_STYLEなんてのがある。うさじさんからはDM_SETDEFIDというものの存在を教えてもらう。
とりあえず先に見つけたBM_STYLEというのを試す。ダメだ。切り替わらない。
次にうさじさんから教えてもらったDM_SETDEFID。
コレだっ!
ぶらぼー。ありがとう、うさじさん。
でもイマイチ使い勝手が良くない。初期フォーカス位置はファイル名順のほうが良かったかな。
カレントディレクトリ変更ダイアログで\\serverとサーバ名だけ入力した時にクラッシュしていたのを修正。
NULLを逆参照してしまったとか言う。
NTだとc:\windows\system\ といった末尾に \ があるディレクトリに移動できないらしい。知らなかった。
8月3日に行った修正の余波を食らった模様。
あれー。Ctrlのアレがこんなところでも影響しているとは。
言われてびっくり、Tabキーが無い。
パン食べながらコーディングしてコーヒー飲みながらテストして良さそうなのでアップロードする。
うわー、最近 Litestepだったのですっかり気付きませんでした。
画面幅/高さからタスクバー分さっ引いて大きさを合わせるようにしていたらタスクバー分、座標位置がずれてた。
あーでもないこーでもないと試行錯誤して振り出しに戻ったりして。
CreateWindow()の座標原点ってスクリーン座標じゃなかったっけ。そっか、これが間違いの原因か。
直したと思うけど、眠いのでもう寝る。テスト? さぁ。
CapsLockが掛かっているとShift+なんとかで頭文字検索が発動しなかったのを修正。
なぜかSFNの代わりにLFNが表示されていたのを修正。
メモリ確保に失敗した場合、すぐに中断せずに処理を継続しようとしていたのを改め、すぐに中止する。
コードを折り畳んでいた時に折り畳み過ぎて、誤動作していた。
\\machine\hoge\の後ろに文字があるかどうかでサーバなのかディレクトリなのかを判断していたところが最後の\の後ろに文字があるかなしやという判定になってしまったため判定負け。
少なくとも8月2日までは正しく動作していたハズ。
使用フォントをMS Pゴシックから固定ピッチフォントのMS ゴシックに変更。
後から見たらはみ出てたりしてみっともない。
キーワードに
追加。今見ると「Explorerのプロパティと同じものをみる方法」なんてのもあったりして、もしかして必要なかったかも。
何も考えずに判定ルーチンをスキップさせてみたらc:\windows\system\..とかいうディレクトリに移動してしまって何ともいえない状態になる。相対パスの正規化ルーチンを通していないらしい。
運悪く、OLE2 D&Dの実装準備としてコンテキストメニューのルーチンからITEMIDLISTを取得する部分を抜き出していたので手間取る。
固定ピッチフォントにあわせてサイズなど微調整。
自動更新時に二回ディレクトリを検索する原因が解った。
ちょっち試行錯誤中。
ITEMIDLISTを取得するところを書き換えていたせいでコンテキストメニューがうまく動作しなくなっていた。
ファイルが無い状態(空のディスクとか検索してノーヒットの状態)でダブルウィンドウモードにすると死ぬ。
Windows 98@FIVAでは平気で動いている。このときDFは、malloc(0)してmemcpy(dst, src, 0)してmemset(dst, 0, 0)ととにかくサイズ0でメモリブロックを操作しているのだが、多分このあたりがマズいのだろう。
なんだかよくわからないが、サイズ0バイトのメモリブロックの取り扱い関係らしい。
我慢しきれなくなったので一覧ウィンドウを自前で描画するようにする。
影響が大きすぎて一筋縄では行かない。
エラーのログを送っていただく。
エラーが出ている場所はほぼ特定しているのでいいのだけど、理由がなんなのか突き止めないと同じ過ちを繰り返しそうで。
FramePtr | ReturnAd | Param#1 | Param#2 | Param#3 | Param#4 | ファンクション名 |
0012FDD8 | 77E53126 | 000000B4 | FFFFFFFF | 00000000 | 0040337E | ntdll!NtWaitForSingleObject |
0012FE5C | 00403FBC | 00145B48 | 00000000 | 00000002 | 00145B48 | kernel32!WaitForSingleObject |
0012FE80 | 00403AB4 | 00145B48 | 0000000A | 00403D0C | 00000111 | !<nosymbols> |
0012FEA4 | 00000009 | 0012FF7C | 00403917 | 00145B48 | 0012FEDC | !<nosymbols> |
えっなんでここで? メインスレッドに死ぬ要素なんて無いじゃん。何か見落とした?
ってあせったけど、こっちはwait中で動いていない。死んだのは予想通りサブウィンドウ側のスレッド。
FramePtr | ReturnAd | Param#1 | Param#2 | Param#3 | Param#4 | ファンクション名 |
00F3FF78 | 0040343D | 00130000 | 00000000 | 00000000 | 0012FE24 | ntdll!RtlSizeHeap |
00F3FF98 | 00080150 | 00000000 | FFFFFFFF | 00010101 | 0012FE24 | !<nosymbols> |
00F3FFB4 | 77E537CD | 0012FE24 | 00080150 | 00000000 | 0012FE24 | <nosymbols> |
00F3FFEC | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | kernel32!TlsSetValue |
あー、HeapSize()にNULL渡しちゃったらダメかあ。確かにダメなような気もする。
このAPI、失敗したら0を返すという仕様になっているのだから、ちゃんと正しく失敗してくれ〜って使い方間違えてる私の言うことではないのかもしれない。
自前で描画するようになってから時々クラッシュしていたのだけど原因が解った。
せっかくだからデータ構造を作り直すことにする。
勤務先で動かしているβ5だと、なぜかWZ EditorをインストールしてからWZ Editorがエディタを開きやがる。xyzcli.exeを開かれてもなあ。
FIVAで動かしているβ6(メモリリーク調査版)だと普通。
あー、解った。ような気がする。正体不明の関連付けに対してWZが起動するように設定されていて、editor.exe text.txt というのが正体不明になってWZがeditor.exeを開いているのか。
で、FIVAには正体不明の関連付けについて設定していないから普通に動くと。
なんで正体不明になるのだ。
昔のようにShellExecute()だと普通に開く。ShellExecuteEx()だと不可解な動作だ。ShellExecuteEx()だと関連付けていないものはUnknownのキーで開いてくれるので便利だったのだけどこういう罠があるとは。
でShellExecuteEx()を実行した時、いったいナニが起こっているのだろうか。
ディレクトリ削除時にエラーが発生するとリソースリークするような流れになっている。んがー。
リソースといってもGDIオブジェクトとかじゃなくて、カーネルオブジェクトのハンドルリーク。closeしないでretrunしちゃってるよ。
複数選択時のリネームがバグってた。
で、リトライの時に連番を指定できない仕様は、番号を入力できるようにしていたので解決できるはずなのでついでに手を入れる。
順位が決定できないときには名前でソートするように変更。
ああっまた遅くなる…。
サブディレクトリに含まれるファイルを移動する時、すでにファイルが存在していても上書きするように設定していたのを変更する。既定値を指定無しとして、ユーザに問い合わせる。
以前は、ディレクトリを発見した時点で問い合わせていたのをやめてサブディレクトリ内のファイルを見つけた時点で問い合わせるように変更したため、その影響がここで発生していた。
現在行っている、ファイルがすでに存在するかどうかの判定処理には無駄がある。捨てて書き直すか。
ファイルがすでに存在する時の処理が、
の二ヶ所にあるのが気になる。同じような処理が二ヶ所に分散しているのが間違いの元。
この時の処理は
というものだけど、保持しているタイムスタンプが、
とちょっとだけ違うので全く同じ処理にはできていない。
先にローカル時間に変換してしまってから処理するというのも手か。
とりあえずダイアログ表示部分についてはコードを折り畳んでみた。
実行ファイルサイズには全然影響が無くてがっかり。
こればっかりはやってみないと結果がわからないので事前に計測するということができない。
Makefileがバグっててメチャメチャびびる。
ソートがバグってると思ってメチャメチャびびったらFIVAがバグってた。
色々書き換えてみたものの特に体感できるほどの効果は得られなかった。
以前に付けていた、ディレクトリも名前を変えてコピーする機能、消したのは失敗だった。
使えなくてがっくりしたのは今日で何度目だ。復活させよう。
ということでさっくりとその辺の処理を削除する。
上書き確認から名前変更キャンセルの連続技を決めた時の挙動が、カレントディレクトリでの処理とサブディレクトリ内での処理で異なっているのを発見。
せっかくだから修正する。
以前に付けていた、ディレクトリも名前を変えてコピーする機能、なんで消したのかといえばディレクトリをコピーする時に日付で比較しても役に立たないから消したのだった。
で、とりあえずディレクトリは上書きするという前提で中に入るようにしたのだった。
さて、どうしたものか。
ではディレクトリをコピーする方向に分岐して、中のファイルについて判定するようにする。
はどうしたものか。
特に「何もしない」時にはディレクトリをコピーしないのか、ディレクトリの中のファイルをコピーしないのか解らん。
行き当りばったりには、カレントディレクトリでのオプションと、サブディレクトリでのオプションを分けてしまうのが楽そうだけども。
ディレクトリ一覧を再取得する時、カーソル位置のファイル名を覚えておいて取得したあとのカーソル位置を同じファイル名を指すようにした。
あ、削除された時のことを考えてないや。
ソートした時にもカーソル位置を動かすようにする。
そしたら、ファイルを削除した時、ソートした時に動かしたカーソル位置のファイルを指すようになってしまって訳が解らなくなる。
これは驚く。
実行ファイルのリソースに突っ込んでいたバージョン情報がβ15のままだったり。
ディレクトリだったらとりあえず上書きコピー、という処理だと名前を変えてコピーできない。んがー。
処理 | ファイル | ディレクトリ |
何もしない | 何もしない | 上書き |
上書き | 上書き | 上書き |
名前を変える | 名前を変える | 名前を変える |
新しいものだけ | 日付判定 | 上書き |
というようにしなければならない。
ファイルが無い時に表示を更新すると死ぬ、というバグ報告を頂いたのでさっそく調査。
理由は単純で、ファイルが無い時にもカーソル位置を調整しようとしているため。ファイルが無いのに、カーソルが指し示しているファイル名はなんだ、と参照してNULLポインタを参照している(のだと思う。空のドライブを接続していないので試せない)。
ううっ面倒だなあ。
動かすには2行追加して1行書き換えればおっけーなのは解っている。ただ、美しくない。
直したものの、直ったかどうかは帰宅してフロッピーディスクドライブでもつなげないことには判らない。
帰宅した頃には具合が悪かったのでそのまま布団にもぐりこむ。睡魔が来た頃にDFのことを思い出したけどそのまま放置プレイ。寝る。
で、修正箇所のテスト。
落ちなくなってる。よしよし。ソースをβ17に戻してデバッガにかける。予想通りの場所でNULLポインタを参照して落ちる。よしよし。
で、色々テストしていたら、メモリリーク発見。んがー。
次に再利用するためにメモリを保持しっぱなしにしておいて次の動作を速くするか、メモリを解放して他のアプリが動きやすくするか悩む。
メモリ取得のオーバーヘッドもスワップに比べれば微々たるモノだし、メモリは解放することに決める。
calloc()を使うのを止めて、ライブラリから削除。
そしたらcalloc()に頼っている部分を見落としていて誤動作していた部分を発見。
ExitWindowsEx()の引き数でEWX_SHUTDOWNを指定したのをEWX_POWEROFFに変更した。
サブウィンドウを閉じるときにカレントディレクトリをメインウィンドウ側に切り替えるように変更。
こうしないとサブウィンドウで開いていたドライブをNT系OSでアンマウントできなくなる。
別件で保護例外出して死んだので、しばらく様子見のあと、公開予定。
ファイルがないときにソートすると落ちる、と報告を頂く。
ソート処理の中で、ファイルがないときには何もせずに制御を戻すようにしていたのだけど…。
と思ったら、ソート後にカーソルを元に戻す処理のところでバグってる。
なんでこんな作りになっているのか、当時の記憶を呼び覚ます。
最初はこんな感じの処理だった。ソートした後にカーソルがふっ飛ぶ。
文字列比較はかなり重い処理だから二度もカーソル位置を戻すのは無駄だ。これは一度だけにしたい。ということでソート処理の前後からカーソル位置を調整する部分を削除。
と、現在に至るわけ。この時のカーソル位置のファイル名を記憶するのがマズい。ファイルがないときには記憶しちゃいかん。
と、ファイルがある時に限定しているので、判定が二重になって無駄だ。
やっぱりソート処理の中でカーソル位置を記憶して復帰させたほうがよさそうだが、途中に一覧を取得するという処理があるのが厄介。
このあたり作り替えるか。