関数を作るにあたって質問があります。
現在、1個〜5個のStringを引数として渡す関数を作っています。
この時の渡し方として、TStringListを用いる方法と、Array of Stringを用いる方法が思い浮かびました。
ちなみに、上記関数を含めた関数群をDLLにしようと思っています。
こういった場合は、どちらを私用するのがベターでしょうか。
又は、他に良い方法はありますでしょうか。
宜しくお願い致します。
回答ではないですが、DLL でDelphiの文字列を渡すのは難しいですよ。
よく検討してください。それから、クラスのインスタンスの受け渡しは
原則できません。ですから TStringList を引数にするのは論外です。
えーと 様
アドバイスありがとうございます。
ということは、配列で渡す方法一択ということでしょうか。。。
一応、作成するDLLはDelphiからしか使用しないという前提を作って、
且つusesにShareMemを追加 & BORLNDMM.DLLも配布という方法をとれば
問題なく文字列を(TStringlistのインスタンスも?)渡せるという認識です。
クラスのインスタンスは、共通のパッケージを使用してコンパイルしたもの
でなければ、DLL を通した受け渡しはできません。ですから、このような場合は
そもそもDLLにする意義があまりないです。
また、ShareMem を使用したとして、使う方の exe も ShareMem を使ってコンパイル
する必要があります。そんな限定的な使用法にして DLL にする必要があるかどうか、
検討してみてください。
えーと 様
背景について説明させて下さい。
(質問に直接関係ないと思い省略していました。余計な手間を取らせてしまい
申し訳ありません。。)
先ず、似た機能を持つアプリケーションを複数(10個程度)作ろうとしています。
そして、それらで共通的に使用する関数を1箇所に纏めたいと考えました。
そうこう考えているうちに、共通となるロジック群を一つのpasファイルに記述し、
各アプリケーションから参照する方法と、今回質問させて頂いたDLLにする方法を
思いつきました。
両方法について検討した結果、共通ロジック群に修正を加える場合、全アプリを
コンパイルし直すより、DLL一つのコンパイルで済む方が良いのではと思いました。
ちなみに、DLLもexeも同じ環境で作成しますし、限定的な使用方法というご指摘
に関しても問題ないと考えています。
(個人的、又は限定される範囲で使用する予定で、公開とかは考えていない為。)
以上になります。
考え方、道筋等に誤りがあれば、お手数ですが再度ご指摘お願い致します。
個人の好みとは思いますが、ShareMem も共通パッケージも使用しないで
一つの pas ファイルを使ってコンパイルした方がかなり楽ではないか、と
思います。
おっしゃるようなことであれば、数が変化する string を受け渡すのに
知っていなければならないことは、他人に説明する必要がないわけですから、
好きにしてよいと思います。
一般的なDLLではなく、パッケージ(bplファイル)にすれば、
stringでもクラスインスタンスでも問題なく渡せますよ。
イメージ的には、Delphi専用DLLとでも言ったらいいでしょうか。
基本的にDelphiでしか使えないことを除けば、DLLと同様に
動的・静的にリンクして使うことが出来ます。
私も仕事で作っているプロジェクトでは、橘さんと同じように
限定した状況であるという前提で、パッケージに組み込んだ
自作の共通関数を大量に使っています。
なお配列かTStringListかという件については、その関数を
呼び出す側の使いやすさの問題ではないでしょうか。
TStringListにした場合は、呼び出し元でいちいちインスタンスを
生成しなくてはなりませんし、配列にした場合は項目数が不定で
多めな場合に指定しにくくなる…結局ケースバイケースに
なってしまいますね。
EXE DLL 両方とも同じバージョンなら
りょうほうともとりあえずできる。
同じバージョンでも、DLL と exe は個別にコンパイルするので、クラスのインスタンスは
異なったクラスのテーブルを参照することになり、DLL を通して受け渡すことは
できません。
こんなのどう?
//EXE
TSetArrayString = function (Memo: TMemo; Text: array of String): String;stdcall;
TSetString = function (Memo: TMemo; Text: String): String;stdcall;
TSetStringList= function (Memo: TMemo; Text: TStringList): String;stdcall;
var
Form1: TForm1;
SetArrayString: TSetArrayString;
SetString: TSetString;
SetStringList: TSetStringList;
hLib: THandle;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
hLib := LoadLibrary('dll_project1.dll');
if hLIB <> 0 then
begin
SetArrayString := TSetArrayString (GetProcAddress(hLib,'SetArrayString' ));
SetString := TSetString (GetProcAddress(hLib,'SetString' ));
SetStringList := TSetStringList (GetProcAddress(hLib,'SetStringList' ));
end
else
begin
Caption := 'NO DLL';
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if hLIB <> 0 then
begin
FreeLibrary(hLib);
end;
end;
procedure TForm1.Button7Click(Sender: TObject);
var
S: String;
R: String;
begin
S := 'SetString';
R := SetString(Memo1,S);
Memo1.Lines.Add(R);
end;
procedure TForm1.Button8Click(Sender: TObject);
var
S: array[0..5] of String;
R: String;
begin
S[0] := '000000';
S[1] := '111111';
S[2] := '222222';
S[3] := '333333';
S[4] := '444444';
S[5] := '555555';
R := SetArrayString(Memo1,S);
Memo1.Lines.Add(R);
end;
procedure TForm1.Button9Click(Sender: TObject);
var
StringList: TStringList;
R: String;
S: String;
begin
StringList := TStringList.Create;
StringList.Add('AAAAAAAAAAAAAAAAAAAAA');
StringList.Add('BBBBBBBBBBBBBBBBBBBBB');
StringList.Add('CCCCCCCCCCCCCCCCCCCCC');
StringList.Add(S);
R := SetStringList(Memo1,StringList);
Memo1.Lines.Add(R);
StringList.Free;
end;
//DLL
function SetArrayString(Memo: TMemo; Text: array of String): String;stdcall;
var
I: Integer;
begin
for I:=Low(Text) to High(Text) do
begin
Memo.Lines.Add(Text[I]);
end;
Result := 'SetArrayString Result String';
end;
function SetString(Memo: TMemo;Text: String): String; stdcall;
begin
Memo.Lines.Add(Text);
Result := 'SetString Result String';
end;
function SetStringList(Memo: TMemo; StringList: TStringList): String; stdcall;
var
I: Integer;
begin
//Memo.Lines.Add(StringList.Text);
for I := 0 to StringList.Count -1 do
begin
Memo.Lines.Add(StringList[I]);
end;
Result := 'SetStringList Result String';
end;
exports
SetArrayString,SetString,SetStringList;
begin
end.
> 同じバージョンでも、DLL と exe は個別にコンパイルするので、クラスのインスタンスは
> 異なったクラスのテーブルを参照することになり、DLL を通して受け渡すことは
> できません。
メソッドってのは内部ではインスタンスポインタを引数に受け取って処理をする。
バージョンが同じなら生成されるコードも同じだから異なったVMTを指していても処理は同じになる。
だからEXEとDLLで別だったとしても処理は可能。実際にやればわかること。
あなたの妄想を書き込んで混乱させるのはやめてもらえませんかね。
>//Memo.Lines.Add(StringList.Text);
> for I := 0 to StringList.Count -1 do
> begin
> Memo.Lines.Add(StringList[I]);
> end;
Memo.Lines.Add (StringList.Text)
だと終了時(DLL開放時)にエラーになる
>だからEXEとDLLで別だったとしても処理は可能。実際にやればわかること。
同じバージョンでコンパイルしたものは相対アドレスは同じコードになりますが、そうでない場合が
ない、と言い切れますか? 共通パッケージの必要性や ShareMem はなんのためにあるか理解してますか?
[Delphi-ML:77472] オブジェクトを返すDLL関数について
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=077472
[Delphi-ML:44863] DLL中の手続きにクラス変数を引き渡す方法を教えてください。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=044863
> 同じバージョンでコンパイルしたものは相対アドレスは同じコードになりますが、そうでない場合が
> ない、と言い切れますか? 共通パッケージの必要性や ShareMem はなんのためにあるか理解してますか?
相対アドレスって何に対する相対アドレスですか?
VMTのことを言ってるなら、テーブル内の関数アドレスは全部絶対アドレスですよ。
あなたこそ本当に理解していますか?
インスタンスを受け渡すことと、ShareMemや共通パッケージは直接的な関係はありませんよ?
ShareMemは単にメモリマネージャを共通化するためのものです。
TStringListの要素数を変更する場合などはShareMemが必要になりますが、
ただ読み取るだけならShareMemを使う必要すらありません。
EXEとDLLが異なったメモリマネージャを使っていても、
それぞれのメモリマネージャで生成と破棄をきちんと行うのであれば、
同一プロセス内の話ですからメモリアクセス自体には何の問題もありませんので。
共通パッケージもEXEとDLLで共通のコードを使うというただそれだけの話で、
共通パッケージとEXE、DLLのVCLバージョンが異なれば使わないのと同じ状態になるのを理解できてますか?
どうも間違った認識を持っているようですが、机上の空論を振りかざす前に実際に試してみてください。
もしくはShareMemや共通パッケージのロード部などのソースコードを実際に読んでみると良いでしょう。
その上でまだ反論があるようでしたら、ただできないできないと喚くのではなく、
具体的に何が問題となるか書いて下さい。
>Memo.Lines.Add (StringList.Text)
>だと終了時(DLL開放時)にエラーになる
なんだけど
if hLIB <> 0 then
begin
Memo1.Free;
FreeLibrary(hLib);
end;
にするとエラーがでない。
DLL側で
function SetString(Memo: TMemo;Text: String): String; stdcall;
begin
Memo.Lines.Add(Text);
Result := 'SetString Result String';
end;
をやると EXE側にあるMemo に DLL側にメモリが使用される
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if hLIB <> 0 then
begin
FreeLibrary(hLib);
end;
end;
をすると DLL開放 -> Memo 開放の順になって Lines のメモリを開放する時に DLL が既に開放されているのでエラーになる
と思う
>相対アドレスって何に対する相対アドレスですか?
>VMTのことを言ってるなら、テーブル内の関数アドレスは全部絶対アドレスですよ。
正確に言うと、MMU使っているから論理アドレスなんだけどね。
まっ、だとしても論理アドレスを相対アドレスとは普通言わないな。
論理アドレスの対義語は物理アドレスですよ。
絶対アドレスとは関係ない。別に正確でも何でもないですが。
>絶対アドレスとは関係ない。別に正確でも何でもないですが。
関係ないと言うか、Windowsはプロテクトモード動くOSだから
アプリは全て論理アドレスなんだけどね。
てっきり、Delphiでプログラムを実行中にモジュール画面を見ると
メソッドのアドレスが、いつも同じアドレスを指しているから
物理アドレスが指定されていると勘違いしている人が多いから
それかな〜っと、思ったんだけど違うみたいだね、俺の勘違いだね。
つまり、絶対アドレス=オフセットアドレスと言う意味でいいの?
それなら、一応ゼグメントに対して相対だよね。
そもそも絶対・相対アドレスと物理・論理アドレスは根本的に概念の異なるものです。
比較できるものではないですし、なぜ物理アドレスなどを持ち出されたのか理解に苦しみます。
はっきり言ってしまえばあなたは勘違いをされているのではなく、単に理解されてないだけかと思います。
「絶対アドレス=オフセットアドレス」などと言ってしまうのが良い例です。
(オフセットとは相対とほぼ同義です)
それから単なる打ち間違いかもしれませんがゼグメントではなくセグメントですし、
Windowsがプロテクトモードで動くと仰るということは最近のOSを指してると思われますが、
最近のOSはセグメント方式ではなくページング方式ですのでセグメントも関係ありません。
(セグメント自体は残されていますがオフセットのためには使われません)
本筋とは関係ない話題で、さらにこれだけ間違いだらけと、一体何が仰りたいんでしょうか?
>そもそも絶対・相対アドレスと物理・論理アドレスは根本的に概念の異なるものです。
>比較できるものではないですし、なぜ物理アドレスなどを持ち出されたのか理解に苦しみます。
概念の話はしてないよ、実際にCPUは物理アドレスのメソッドを実行するのは理解出来るよね?
EXEとDLLが参照するアドレスを物理アドレスにどう変換しているか重要だと思うけど。
>「絶対アドレス=オフセットアドレス」などと言ってしまうのが良い例です。
>(オフセットとは相対とほぼ同義です)
???、マシン語で
自分自身から何バイト目と指定するのを相対アドレス指定
オフセットアドレスを直接指定するのを絶対アドレス指定と言う時もあるよね。
物理アドレスじゃ無いと言ってから、てっきり、これだと思ったけど
それだと、絶対アドレスって、何を言っているの具体的に教えて。
>それから単なる打ち間違いかもしれませんがゼグメントではなくセグメントですし、
本当だ、打ち間違えた、ありがとうね。ついでに俺も
>VMTのことを言ってるなら、テーブル内の関数アドレスは全部絶対アドレスですよ。
>あなたこそ本当に理解していますか?
関数じゃなくメソッドね、細かいから指摘するのも悪いと思ったけど
一応、VMTのMだからね。
今回の質問に本当に物理アドレスが重要だと思いますか?
ここは関係ない知識を披露する場ではありません。
お二方ともこれ以上の荒らしはやめてください。
こんなのどう?
http://wisdom.sakura.ne.jp/programming/asm/assembly5.html
ツイート | ![]() |