Skip to content

Latest commit

 

History

History
158 lines (104 loc) · 7.66 KB

ARCHITECTURE.md

File metadata and controls

158 lines (104 loc) · 7.66 KB

アーキテクチャ

全体の概観と、設計上の重要な点を説明します

概観

knowbugのプログラムは「サーバー」と「クライアント」の2つのプログラムからなります

サーバーはHSPランタイムと直接的に連携します。 ランタイムから情報を読み取ること、クライアントからの指示をランタイムに伝えることが目的です

クライアントはデバッグウィンドウを表示します。 サーバーからもらったデータをユーザーに表示すること、ユーザーの操作をサーバーに伝えることが目的です

                    通信
サーバー (ランタイム) <------> クライアント (デバッグウィンドウ)

コード地図

ソースコードは src ディレクトリにあります

  • src
    • knowbug_client: クライアントの実装 (HSP3)
    • knowbug_core: サーバーの実装の主要部分 (C++)
    • knowbug_dll: サーバーの実装のDLL部分 (C++)

クライアント

主要な実装は kc_*.hsp にあります。(kc = knowbug_client)

クライアントの実装にデバッガ特有の部分は含まれていません。 普通のGUIアプリケーションです

kc_main.hsp はアプリのエントリーポイント (入口、最初に実行される部分) です。 サーバーとの通信部分もここに含まれています。 kc_app.hsp がサーバーとの通信に関する実装をもつ必要をなくし、UIの機能の実装に集中できるようにするためです

kc_app.hsp は主要な機能の実装を含んでいます。

mod_*.hsp という名前のファイルは汎用的な機能を提供するモジュールです。 詳細はファイル内のコメントを参照してください

サーバー

サーバー側の実装は knowbug_dllknowbug_core の2つのプロジェクトに分かれています

knowbug_dll は、配布時に hsp3debug.dll という名前になる、HSPのランタイムからロードされるDLLです。 アプリのエントリーポイント (入口) となる、以下の関数を公開します:

  • DLLのロード時に呼ばれる関数 (DllMain)
  • HSPランタイムから呼ばれる関数 (debugini, debug_notice)

クライアントを起動して通信すること、knowbugのデータを所有することも、ここの役目です

knowbug_core は主要な機能の実装から汎用的なモジュールまですべて含みます

オブジェクトAPI

HSPのランタイムに関する情報は HspObjects というオブジェクトに問い合わせて得る、というかたちにしています。 情報の対象となるエンティティ (例えば配列の要素) を指し示すのには HspObjectPath を使います

HspObjectPath (オブジェクトパス) は、HSPのオブジェクトへの到達経路を表します。 例えば「モジュール @ にある配列変数 a の添字1の要素」は、次のようなかたちのパスで表します:

    ルート → モジュール(`@`) → 静的変数(`a`) → 配列要素(1)

パスを使うのは次のような理由からです:

  • 経路を遡ることで、オブジェクトの生存判定を確実に行える
    • 配列の要素や命令のパラメータなどのオブジェクトは消滅することがあります
    • 消滅したオブジェクトへのアクセスは実行時エラーにつながるおそれがあり、危険です
  • 情報の取り方をknowbug側の都合に合わせて設計できる
  • 情報を取得する部分と加工する部分を切り離せる

HspObjects にパスを渡す、主な利用者は以下の2つです:

  • HspObjectWriter: データを文字列表記に変換する。詳細ウィンドウに出てくるもの
  • HspObjectList: オブジェクトの構造を表すリスト。リストビューに出てくるもの

hsx (HSP SDK Extension)

hsx_* はHSPランタイムの情報を読み取る処理をまとめたものになっています。 HSPランタイムの事情と、knowbug固有の機能を分離するために存在します

サーバーはランタイムからもらったオブジェクト (HSPCTXHSP3DEBUG) からポインタをたどることで、ランタイムの情報にアクセスできます。 これには注意する点があります:

  • HSPランタイム側のデータの持ちかたは、スクリプトを実行するときの効率や整合性を考慮して設計されています。
    • 関連するデータが複数の構造体に分散して配置されていたり、一部の情報は計算で算出する必要があったりします
  • ポインタの脱参照時のNULL検査や、配列アクセス時の境界検査が必要です
    • メモリアクセス違反による実行時エラーが起こると、ランタイムごとクラッシュしてしまうことになります

hsxはランタイムのデータにアクセスして、必要な情報を取得するための関数を提供します。 これは以下の利点があります:

  • 分かりやすい
    • 情報を取得する際に、その情報を取得する関数を呼ぶだけなので分かりやすい
    • データがどこにあるのか、どう計算するのか、ということを考えなくてよい
  • 安全
    • 関数の内部で必要な検査が行われる

横断的な関心事

文字列のエンコーディング

エンコーディングごとに文字列のクラスを用意しています

  • knowbugは複数のエンコーディングを扱う必要があります
    • shift_jis: HSPの非UTF-8版のランタイムで使う
    • UTF-8: HSPのUTF-8版のランタイムと、knowbugのソースコードで使う
    • UTF-16: Windows APIで使う
  • エンコーディングごとのクラスは、エンコーディングの混同を防ぐことと、エンコーディングの変換を簡略化してくれます
  • 詳細は encoding.h のコメントを参照してください

その他

プロセス構造

サーバーはHSP3のランタイムプロセスによってロードされるDLLなので、ランタイムと同一のプロセス空間にいます。 クライアントはサーバーによって起動される、独立したプロセスです

    ランタイムプロセス
    +------------------+
    | hsp3.exe         |       クライアントプロセス
    |                  |       +----------------+
    | hsp3debug.dll <--+-----> | knowbug_client |
    +------------------+       +----------------+

サーバーとクライアントは、ウィンドウメッセージを使って双方向的に通信します


その他: 背景知識

以下のことについて知っておくとよいです

  • プロセス
  • 文字コード (文字列のエンコーディング)
  • ウィンドウメッセージ、メッセージキュー

その他: HSP側の資料

  • HSPのインストールディレクトリにhspsdkディレクトリがあり、その下にある hsp3dll.txt, hsp3code.txt はHSPの内部構造を理解するにあたって非常に便利です
  • OpenHSPのソースコードを必要に応じて読みます

その他: 過去のissues


ARCHITECTURE.mdとは何か (英語)