現在Cで書かれたヘッダをDelphiに移植しております。
そこに
int XDWAPI XDW_MergeXdwFiles(const char** lpszInputPaths, int nFiles,
const char* lpszOutputPath, void* reserved );
という関数があるのですが、このchar**の移植について悩んでいます。
lpszInputPathsには255バイト以内で複数のファイルのフルパス
nFilesには入力するファイルの個数
lpszOutputPathにはその複数のファイルを結合した結果ファイルの出力フルパス
reservedはダミーのヌル
を入力します。
とりあえず、char**の正確な移植方法がわかりませんのでPointerにして
実験しております。
■移植宣言
function XDW_MergeXdwFiles(const lpszInputPaths: Pointer; nFiles: Integer;
const lpszOutputPath: PChar; reserved: pointer): Integer; stdcall;
下記は実験コードです。
InFilesはTStringsで渡してきます。
MakeFileNameはStringです。
■テスト1
var
f: array[0..2] of pCHar;
begin
f[0] := PChar(InFiles[0]);
f[1] := PChar(InFiles[1]);
f[2] := PChar(InFiles[2]);
Result := XDW_MergeXdwFiles(@f, 3, PChar(MakeFileName), XDW_NULL);
としましたら成功しました。
■テスト2
var
f: array of pCHar;
begin
SetLength(f, InFiles.Count);
for i := 0 to InFiles.Count - 1 do
f[i] := pChar(InFiles[i]);
Result := XDW_MergeXdwFiles(@f, InFiles.Count, PChar(MakeFileName),
XDW_NULL);
としましたら失敗しました。
エラーコードは「パス名の指定が正しくない」です。
しかし、テスト1とまったく同じデータを渡しています。
テスト1と2では自分の中ではほぼ同等のデータが@fで
渡されていると思っているのですが、何が違うのでしょうか?
実際には渡してくるデータの個数がばらばらなので
できればテスト2を実用化したいと思います。
よろしくご教授ください。
---------------------------------
太田剛文
---------------------------------
太田さん:
> ■テスト1
>
> var
> f: array[0..2] of pCHar;
> begin
> f[0] := PChar(InFiles[0]);
> f[1] := PChar(InFiles[1]);
> f[2] := PChar(InFiles[2]);
> Result := XDW_MergeXdwFiles(@f, 3, ...);
>
> としましたら成功しました。
>
> ■テスト2
>
> var
> f: array of pCHar;
> begin
> SetLength(f, InFiles.Count);
>
> for i := 0 to InFiles.Count - 1 do
> f[i] := pChar(InFiles[i]);
>
> Result := XDW_MergeXdwFiles(@f, InFiles.Count, ...);
>
> としましたら失敗しました。
> テスト1と2では自分の中ではほぼ同等のデータが@fで
> 渡されていると思っているのですが、何が違うのでしょうか?
C言語からの型変換の問題ではありません。 静的配列と動的配列では
Delphi がメモリに格納する形式が違うのです。
配列を F とします。 静的配列の場合、@F は最初の要素のアドレスを
指します。 F のインデックスが0から始まるのであれば、@F=@F[0] です。
これに対して動的配列では、@F は最初の要素のアドレスを指さず、
「最初の要素のアドレスを指すポインタの置かれているアドレス」を
指しています。 ですので @F<>@F[0] です。 静的配列と同じように
するには、@F[0] と書けば良かったと思います。
#これは、動的配列では SetLength が呼び出され、より大きい別のメモリ
領域を確保しなければならない場面があることによる仕様です。
ちなみに string 型についても同じようなことが言えます。 string[255]
などとすると静的配列になります。 string と string[255] で、@S=@S[0] に
なるかどうか試してみると、理解が深まると思います。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
> これに対して動的配列では、@F は最初の要素のアドレスを指さず、
> 「最初の要素のアドレスを指すポインタの置かれているアドレス」を
> 指しています。 ですので @F<>@F[0] です。 静的配列と同じように
> するには、@F[0] と書けば良かったと思います。
> #これは、動的配列では SetLength が呼び出され、より大きい別のメモリ
> 領域を確保しなければならない場面があることによる仕様です。
なるほど~
よくわかりました。
array ofの動的配列は目には見えないですが裏では
線形リストのようになっているのですね。
その先頭ポインタのポインタという意味ですね。
早速試してみます。
ありがとうございました。
---------------------------------
太田剛文
---------------------------------
高木:
>> これに対して動的配列では、@F は最初の要素のアドレスを指さず、
>> 「最初の要素のアドレスを指すポインタの置かれているアドレス」を
>> 指しています。 ですので @F<>@F[0] です。 静的配列と同じように
>> するには、@F[0] と書けば良かったと思います。
>> #これは、動的配列では SetLength が呼び出され、より大きい別のメモリ
>> 領域を確保しなければならない場面があることによる仕様です。
太田さん:
> array ofの動的配列は目には見えないですが裏では
> 線形リストのようになっているのですね。
> その先頭ポインタのポインタという意味ですね。
リストというよりも、静的配列へのポインタです。 静的配列とは、置かれる
メモリ上の場所に違いがありますが…… (動的配列の内容は、ヒープに
置かれます)
> リストというよりも、静的配列へのポインタです。 静的配列とは、置かれる
> メモリ上の場所に違いがありますが…… (動的配列の内容は、ヒープに
> 置かれます)
理解が違っていました。
ではSetLengthを使うとMMがヒープに静的配列を作成し、
そのポインタがarray of の変数に代入される、ということですね。
話は戻りまして最初の質問は見事解決しました。
@f[0]で渡して成功しまして、そのあと高木さんの話を参考に
そのままfを渡しましたら、それも動作しました。
ありがとうございました。
---------------------------------
太田剛文
---------------------------------