今日、なでしこ1.5321がリリースされました!今回のバージョンアップには、大分頑張って貢献しました。せめて長期休暇中だけでもコミットしておきたいわけですよ。
というわけで、今回のバージョンアップで関わった部分:
前のバージョン(1.531)はリリースも遅めで不具合が多かったため、今回のバージョンアップまでのスパンがなんだか短かったですね。それで、本当はマニュアル探査艦周りも修正したかったのですが、暇がありませんでしたf(^^; まぁ、ぼちぼちやっていきます。
今日、なでしこ1.5321がリリースされました!今回のバージョンアップには、大分頑張って貢献しました。せめて長期休暇中だけでもコミットしておきたいわけですよ。
というわけで、今回のバージョンアップで関わった部分:
前のバージョン(1.531)はリリースも遅めで不具合が多かったため、今回のバージョンアップまでのスパンがなんだか短かったですね。それで、本当はマニュアル探査艦周りも修正したかったのですが、暇がありませんでしたf(^^; まぁ、ぼちぼちやっていきます。
今回は、「ディスクサイズ」命令の修正を具体例として、 Turbo Delphi でプログラムのソースコードを追う方法を見ていきます。
まず、なでしこプロジェクト(EXEGroup.bdsgroup)を Turbo Delphi で開いたら、今回修正したい「ディスクサイズ」命令が定義されている場所を見つけましょう。ファイルを横断検索するには、メニューから「検索 - ファイル検索」もしくは「Shift + Ctrl + F」です。
「ディスクサイズ」と入力して検索すると、下のペインに検索結果が一覧表示されます。ペインというのは、こういった情報をまとめて表示するひとまとまりのエリアのことです。設定によっては右下など別の場所に表示されるかも知れません。検索結果は、こんな感じでツリー表示されます:
[-] C:\svn\nadesiko\hi_unit\dll_file_function.pas dll_file_function.pas(2969): AddFunc ('ディスクサイズ','{=?}Aの',648, sys_getDiskSize,'ディスクAの全体のバイト数を返す。','でぃすくさいず');
AddFunc という命令を書いた行がヒットしました。
AddFunc ('ディスクサイズ','{=?}Aの',648, sys_getDiskSize,'ディスクAの全体のバイト数を返す。','でぃすくさいず');
この AddFunc
というのが、なでしこのシステム命令を登録する重要な命令です。第1引数から順番に、なでしこにおける命令名、なでしこでの引数の与え方(助詞など)の定義、命令ID、実際に Delphi 側が実行するハンドラ、命令の簡単な説明、命令の読み、となっています。
では、なでしこの「ディスクサイズ」命令を実行した時に実際に呼び出される処理 sys_getDiskSize
(第4引数) はどこで定義されているのでしょうか。今度はこの sys_getDiskSize
で検索をかけると、次のような結果になります:
[-] C:\svn\nadesiko\hi_unit\dll_file_function.pas dll_file_function.pas(2045): function sys_getDiskSize(args: DWORD): PHiValue; stdcall; dll_file_function.pas(2969): AddFunc ('ディスクサイズ','{=?}Aの',648, sys_getDiskSize,'ディスクAの全体のバイト数を返す。','でぃすくさいず');
最初の検索で出てきた AddFunc の他に、 function sys_getDiskSize(args: DWORD): PHiValue; stdcall;
という sys_getDiskSize
の関数定義らしき行が見つかりました。
function sys_getDiskSize(args: DWORD): PHiValue; stdcall;
検索結果ペインでダブルクリックすれば、ヒットしたファイルのその行に飛ぶことができます。
function sys_getDiskSize(args: DWORD): PHiValue; stdcall; var p: PHiValue; sp: string; iFree, iTotal: TLargeInteger; begin p := nako_getFuncArg(args, 0); if p = nil then p := nako_getSore; sp := hi_str(p); GetDiskFreeSpaceEx(PChar(sp), iFree, iTotal, nil); Result := hi_newFloat(iTotal); end;
慣れていないと分かりづらいので、 Delphi の関数定義について説明しておきます。基本的な書式は次の通りです:
function 関数名 (引数1: 型1, 引数2: 型, …): 返り値の型; var ローカル変数A: 型A; ローカル変数B: 型B; … begin 処理 … Result := 結果 end;
特徴的なのは、ローカル変数をメイン部分の前で前方宣言していることと、返り値を Result という特別な変数に代入する点でしょう。
前置きが長くなりましたが、ディスクサイズを取得する処理 sys_getDiskSize
の内容を追っていきます。
これで、「ディスクサイズ」命令の内容は分かりました。ところが、肝心のディスクサイズ取得はシステム命令で行っているようなので、変更のしようがありません。ということで、ソースコードの追跡はこの辺で諦めて、修正ステップに移りましょう。
今回修正したいのは、存在しないディスクを指定したときに取得される値が変になる現象です。これでは困るので、代わりに-1を返すようにするのが目的です。
ということで、後はディスクが存在するかチェックして条件分岐するだけです。…が、ディスクの存在をチェックする命令なんて知らないので、今回はここでまた検索を駆使しました。なでしこの「フォルダ存在」命令を調べれば、 Delphi でフォルダの存在を判定する命令が何か分かりますね。
同じようなステップで検索すればすぐに分かるので、読者の宿題ということにして結果だけ書くと、 DirectoryExists
命令を使えばいいことが分かりました。修正したソースコードは以下:
if DirectoryExists(sp) then begin GetDiskFreeSpaceEx(PChar(sp), iFree, iTotal, nil); end else begin iTotal := -1; end;
修正完了!です。セットで修正した「ディスク空きサイズ」命令も、すぐお隣りにあるので同様の修正ですぐ終わりました。実は今回の修正だけでも、なんと合計5回以上の検索を駆使しています。
このように、巨大なプログラムを扱う上では、検索能力が必須と言っても過言ではありません。検索してコードを読んでまた検索するヒットアンドアウェイが基本戦法というわけです。
記事を書くにあたって Delphi の資料を探していたら、なんと昔クジラさんが書いた資料に行きあたりました!内容的には多少古いようですが、今まで参考にしていた他の資料よりも細かくかつ分かりやすく解説してくれていたので非常に助かりました。