Create  Edit  Diff  Phillro Industries  Index  Search  Changes  History  Source  RSS  Note  wikifarm  Login

Apolloの作り方

ソースの入手方法

ソースを入手するには次の二つの方法があります。

  1. (a)ソース付きのパッケージをダウンロードする。
  2. (b)cvsからダウンロードする。

(a)ソース付きのパッケージをダウンロードする。

http://sourceforge.jp/projects/apollo/files/

のZIPパッケージ(ap-840b.zip など)にソースが入っています。

(b)cvsからダウンロードする。

http://sourceforge.jp/cvs/?group_id=234

に cvs からダウンロードする方法が書いてあります。

* cvs コマンド自体を入手する方法は?

ソースを変えてうまくいったら

ap-dev@freeml.com メーリングリストで報告して下さいませ。

開発用メーリングリストに参加するには、下記のページを開けば何とかなるでしょう。

http://www.freeml.com/ctrl/html/MessageListForm/ap-dev@freeml.com

コンパイルの仕方

Delphi には Delphi.exe でコンパイルする方法と dcc32.exe でコンパイルする方法とがあります。

  • Delphi.exe は Windows 流の IDE(integrated development environment, 統合開発環境)で、
  • dcc32.exe はコマンドラインツールです。

Delphi.exe でコンパイルする方法

Delphi.exe で Apollo をコンパイルするには、

(1)zipパッケージ? か、cvs? から Apollo のソースを取得する。

(2)(必要なら)$(Apollo)/src/ ディレクトリにある conf_opt.sample を conf_opt.rb? に変更して、config.bat? を実行して Delphi や Apollo に関する設定を行う。

* どのような時に「必要」で、どのような時には「必要でない」のか?

(3)Delphi で Phi.dpr? を読込む。

* 拡張ライブラリをコンパイルする場合は?

(4)「プロジェクト(P)」−「Phi を再構築(B)」でコンパイルする。

* 2回目からは Ctrl+F9(プロジェクト−コンパイル)でも構いませんが、最初は「再構築」にする必要があります。これは、Phiの本体のコンパイルと拡張ライブラリのコンパイルとでは、コンパイルに必要な条件が異なっており、コンパイル済みのユニット(DCUファイル)が別の条件で作成されている可能性があるためです。

(5)Apollo.exe を起動中に Delphi で再構築/コンパイルすると次のように出るでしょう。これも確認してください。こうなるのが正常です。Apollo.exe を終了させてコンパイルすれば目的の phi.so が作成されます。

[致命的エラー] ファイル 'C:\Program Files\apollo\bin\phi.so' を作成できません

もし、Apollo.exe の実行中であるにもかかわらず、上のメッセージが出ない場合には、「プロジェクト」−「オプション」−「ディレクトリ/条件」の「出力ディレクトリ」が$(Apollo)/bin のディレクトリと一致しているかどうかを見てください。一致していない場合には、(2)のconf_opt.rb? を作成して、config.rb? または config.bat? を実行する必要があるでしょう。

dcc32.exe でコンパイルする方法

  • config.bat までは上記と同様。
  • dcc32 -B phi (あるいは phi.dpr) で再構築できる (上記のPhi を再構築(B))。-B を付けないとコンパイル (上記の Ctrl+F9) になる。

--moriq


ご意見・ご質問(comment plugin is disabled).


クラスを追加する方法

何を:

  • Delphiの標準ライブラリのクラスを
  • どこからか拾ってきたライブラリを

どこに:

  • Phi の本体に
  • Phi の拡張ライブラリに

追加する場合とがあります。

Delphi のクラスを Phi の本体のライブラリに追加する方法

http://www.freeml.com/ctrl/html/MessageForm/ap-dev@freeml.com/1192/

作業内容を以下に.

1.uAnimate.pas (添付ファイル)を Apollo/src/u に追加

* 似たようなクラスのファイルをコピーして、クラス名の部分をエディタの一括変換で作っておき、以下の作業を行って、コンパイルしてみて、変更を加えるのが簡単か?

2.Apollo/src/exports.inc? に以下の行を追加.

{$IFDEF VCL}
exports
  ap_cAnimate,
  ap_iAnimate;
{$ENDIF}

* 「{$IFDEF VCL}」はDelphiのヘルプを見て、VCLでしか定義されていない場合(CLXに対応するクラスがない場合)に付けます。

3.$(Apollo)/src/PhiMainUnit.pas? の uses のなるべく最後の方に以下を追加

{$IFDEF VCL}
  uAnimate,
{$ENDIF}

4.$(Apollo)/src/PhiMainUnit.pas? の Init_phi の Init_xx の並びの最後の方に以下を追加

{$IFDEF VCL}
  Init_Animate;
{$ENDIF}

5.$(Apollo)/src/phi.dpr の uses に以下を追加.

{$IFDEF VCL}
  uAnimate,
{$ENDIF}

6.Pythia.batPhiProp.bat を実行


ご意見・ご質問(comment plugin is disabled).


拾ってきたライブラリや Delphi のクラスをPhiの拡張ライブラリとして追加する方法

  • プロジェクト→オプション→パッケージで「実行時パッケージを使って構築」に注意。

ap-dev:1447 PNGObject。pngobj.dpr


ご意見・ご質問(comment plugin is disabled).


オブジェクトの変換

Delphiのオブジェクトをrubyのオブジェクトに変換する、rubyのオブジェクトをDelphiのオブジェクトに変換する。

コピー型の変換と参照型の変換がある。

単純なクラスのコピー型の変換は

  1. ap_Integer(DelphiのInteger型をrubyのオブジェクトに変換する)
  2. dl_Integer(rubyのInteger型をDelphiのオブジェクトに変換する)

イベントハンドラの作り方

* よくわからぬのお・・。tk

たぶん、apollo.so に追加する場合と、拡張ライブラリに追加する場合とでは異なる。

イベントハンドラ呼び出しの仕組み

次のような順番になっている。

  1. Delphiのイベント発生
  2. DelphiのOnXXハンドラを呼び出し
  3. DelphiのOnXXハンドラの中でApolloのハンドラを呼び出す。DelphiのオブジェクトからApolloのオブジェクトに変換し、Apolloのハンドラがあれはそれを呼び出す
  4. 戻ってきたら、戻り値をDelphiの変数に変換して終了する
  5. Delphiのイベント機構に戻る。

(Apollo)/Apollo/src/ext/internet/InternetHandle?.pas で OnError? イベントを説明すると、次のような順番になる。

$(Apollo)/src/ext/internet/internet.dpr
function ClientSocket_new(This: Tvalue): Tvalue; cdecl;
var
  real: TClientSocket;
begin
  real := TClientSocket.Create(nil);
  result := CompoAlloc(This, real);
  if @real.OnConnect = nil then real.OnConnect := Handle.doConnect;
  if @real.OnConnecting = nil then real.OnConnecting := Handle.doConnecting;
  if @real.OnDisconnect = nil then real.OnDisconnect := Handle.doDisconnect;
  if @real.OnRead = nil then real.OnRead := Handle.doRead;
  if @real.OnWrite = nil then real.OnWrite := Handle.doWrite;
  //
  if @real.OnError = nil then real.OnError := Handle.doError;
  ap_obj_call_init(result, 0, nil);
end;
$(Apollo)/src/ext/internet/InternetHandle.pas
procedure TInternetHandle.doError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
  recv, data: Tvalue;
begin
  recv := TComponent(Sender).tag;
  data := rb_ary_new;
  rb_ary_push(data, rb_intern('on_error'));
  rb_ary_push(data, recv);
  rb_ary_push(data, CustomWinSocket_alloc(cCustomWinSocket, Socket));
  rb_ary_push(data, INT2FIX(Ord(ErrorEvent)));
  ret := PhiCallProtect(data);
  if ret <> Qnil then ErrorCode := dl_Integer(ret);
end;
  1. DelphiのOnErrorイベントが発生するとDelphiがOnErrorハンドラを呼び出す。
  2. OnErrorハンドラにはあらかじめ doError メソッドが割り当てられているので(real.OnWrite? := Handle.doWrite の部分)、イベント発生とともに、TInternetHandle.doError が呼び出される。
  3. TInternetHandle?.doError は「PhiCallProtect(data);」でApolloのハンドラを呼び出す。
    1. そのためにまずrubyの配列オブジェクトdataを作成し(data := rb_ary_new)、
    2. メソッド名、レシーバ、引数の順番でpushしていく。
    3. 引数のDelphiのオブジェクトはApolloのオブジェクトに変換してからpushする(CustomWinSocket_alloc(cCustomWinSocket, Socket))。
  4. 戻ってきたら、戻り値をDelphiの変数に変換して終了する
  5. Delphiのイベント機構に戻る。

主要なメソッド

「#{ap_class_name}」の部分は Apollo でのクラス名に置き換えてください。

ap_class_name は apollo でのクラス名。dl_class_name は Delphi でのクラス名。

TPhi_#{ap_class_name}?

ap-dev:1782

type
  TPhi_DBEdit = class(TDBEdit)
  published
    property IsMasked;
    property EditText;
    property Text;
  end;

というのは、Delphiでの技法で、独自クラスを定義することによって、本来は Public や Protected のスコープ?であった関数やプロパティを Published のスコープに変更するという方法です。

Apolloでは Published であれば自動作成の対象となり、それ以外のスコープだと自動作成の対象になりません。従って、このような方法でスコープを変えることは、これらのプロパティを自動作成の対象にすることを意味します。

xxでは TPhi_ から始まる名前を持つクラス(TPhi_DBEdit)は Phi_ の無いクラス(TDBEdit)と同視するようになっています。

Prop_set_string? ( This, v: Tvalue )

$(apollo)/src/u/uProp.pas?

$(delphi)/Source/Rtl/Common/TypInfo.pas? の SetStrProp? で文字列プロパティにセットする。引数としては This:レシーバ と v:値 しかとらない。プロパティ名は rb_frame_orig_func で「最後に実行された ruby メソッド」を使って取得する。

SetStrProp? は published なプロパティにしかセットできない。この問題を回避するためには TPhi_#{ap_class_name} という自前のクラスを作って、プロパティを published にしてしまうという方法がある。

* GetStrProp でも同じ、String 以外の型でも同じ。Get/SetXxxProp? の代表例ということ。

CompoAlloc? と TmpAlloc?

uAlloc.pas? で定義されている。どちらも rb_data_object_alloc で Rubyオブジェクトを作成するが、TmpAlloc はそれだけを行うが、CompoAlloc では PhiObjectList? に Delphiオブジェクトを登録し、Rubyオブジェクトに @events={} というハッシュのクラス変数を定義する。

Rubyオブジェクトが消えないようにする仕組み に関係すると思われる。

ap-dev:1806http://cvs.sourceforge.jp/cgi-bin/viewcvs.cgi/apollo/apollo/src/u/uImage.pas.diff?r1=1.3&r2=1.4

function Image_alloc(klass: Tvalue; real: TImage): Tvalue;
begin	 begin
  #result := TmpAlloc(klass, real);
  #            ↓
  result := CompoAlloc(klass, real);
  Image_setup(result, real);
end;

* この違いを、言葉で説明すると、どう違うんでしょう??

* TmpAlloc は「一時的に」Rubyのオブジェクトを作成し、CompoAlloc は「コンポーネントとして」Rubyのオブジェクトを作成する。というのは、分かったような、分からない説明。TmpAllocは親オブジェクトのメンバーオブジェクトを参照する場合によく使われる。 comprare pillola sildenafile farmaci Comprar Viagra sin receta cumpara Cialis Soft Tabs agora Λεβιτρα agora

CompoSetup?

$(apollo)/src/u/uComponent.pas? で定義され、

$(apollo)/src/Pythia.pas? で外部ライブラリのメソッドとして呼び出し可能になっている。

Component クラスの承継クラスのための一般的な initialize (new メソッドの引数の処理)を行う。すなわち、

ap_obj_call_init?

#{ap_class_name}_setup?

ap_class_name は apollo でのクラス名。dl_class_name は Delphi でのクラス名。

#{ap_class_name}_event_handle?

#{ap_class_name}_alloc?

ap_#{ap_class_name}? ( dl_obj )

DelphiのオブジェクトをApolloのオブジェクトに変換する。コピーになるので、作成された Apollo オブジェクトを変更しても、そのままでは Delphi オブジェクトは変更できない。

変更を Delphi オブジェクトに反映させるためには dl_#{ap_class_name}? ( ap_obj ) で、Apollo オブジェクトを Delphi オブジェクトに変換し、その Delphi オブジェクトを使って反映させる必要がある。 

* Delphi オブジェクトを直接参照する Apollo オブジェクトを作成したい場合にはap_i#{ap_class_name}? を使う。

ap_i#{ap_class_name}? ( dl_obj, dl_owner )

Delphi オブジェクトの内部オブジェクトを取り出す場合に使う。(「i」は「instance」か?、「internal」か?)

http://cvs.sourceforge.jp/cgi-bin/viewcvs.cgi/apollo/apollo/src/ext/dialogs/dialogs.dpr.diff?r1=1.6&r2=1.7&sortby=date

function ColorDialog_custom_colors(This: Tvalue): Tvalue; cdecl;
var
 real: TColorDialog;
begin
 real := ap_data_get_struct(This);
 result := ap_iStrings(real.CustomColors,This);
end;

* 内部オブジェクトのコピーを取り出す場合には ap_#{ap_class_name}?

ap_data_get_struct と ap_data_get_object

function ActionList_set_actions(argc: Integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  real: TActionList;
  args: array of Tvalue;
  CAction: TContainedAction;
begin
  if argc < 2 then ap_raise(ap_eArgError, sToo_few_args);
  SetLength(args, argc);
  args := argv;
  real := ap_data_get_struct(This);
  ap_data_get_object(args[1], TContainedAction, CAction);
  real.Actions[FIX2INT(args[0])] := CAction;
  result := args[1];
end;

* ApolloオブジェクトからDelphiオブジェクトを取り出す仕組み?

* どう違うのか?

* なぜ、「CAction := ap_data_get_struct(args[1]);」ではないのか?

* TContainedAction には tag がないのか?

ap_i#{ap_class_name}_v?

Init_#{ap_class_name}?


ご意見・ご質問(comment plugin is disabled).


Last modified:2011/07/19 17:43:12
Keyword(s):
References: