使用可能な SOAP インポーターには新しすぎる SOAP API を呼び出す必要がある Delphi 7 アプリケーションがあります。私は、D7 が SOAP API を呼び出すには多大な労力が必要であることに満足しています。しかし、私は Delphi XE2 も持っており、SOAP をインポートして非常にうまく呼び出すことができます。そこで、soap インターフェイスの必要な部分を公開する単純な dll ラッパーを XE2 で作成しました。XE プログラムから dll を呼び出すことができます。
Delphi7 では、XE から SOAP API インポート ファイルを取得し、{$SCOPED_ENUMS ON} 定義と、使用できない SOAP ラッパーを呼び出す初期化セクションを削除し、文字列全体をワイド文字列に変更しました。それはコンパイルされます。文字列の受け渡しを機能させ、すべてを stdcall にすることを避けるために、ShareMM を有効にして FastMM を使用しています。
私がこのようにしようとしている理由は、コードの 90% が XE2 SOAP インポーターによって生成されるため、それが機能する場合、SOAP shim のコーディングと保守が非常に簡単になるためです。 D7 アプリを最新の Delphi に移行します。コードはほとんど変更されません。
しかし、実行すると、奇妙な文字列が表示されます (結果としてアクセス違反が発生します)。問題をより明確にするために、SOAP コードを使用しない単純な関数があります。
Delphi7 exe から DelphiXE2 dll にワイド文字列を渡すと、文字列の長さは 2 倍になります (Length() 関数による) が、一致するデータ変換はありません。したがって、D7 のワイド文字列 "123" は XE2 では "1234...." になります。ここで、.... はたまたまスタックにあるガベージです。バイト配列として表示すると、両方とも期待どおり半分ゼロのバイトを持ちます。
XE2 dll から D7 にワイド文字列を渡すと、ミラー効果が得られます。文字列の長さは半分になり、文字列は単純に切り捨てられます ("1234" は "12" になります)。
あなたがそれを要求することを知っているので、コードを貼り付けています。
Delphi XE2 では、次の関数をエクスポートしています。
// testing
function GetString(s:string):string; export;
function AddToString(s:string):string; export;
implementation
function GetString(s:string):string;
begin
Result := '0987654321';
end;
function AddToString(s:string):string;
begin
Result := s + '| ' + IntToStr(length(s)) + ' there is more';
end;
Delphi 7 では:
function GetString(s:widestring):widestring; external 'SMSShim.dll';
function AddToString(s:widestring):widestring; external 'SMSShim.dll';
procedure TForm1.btnTestGetClick(Sender: TObject);
var
s: widestring;
begin
s := widestring('1234');
Memo1.Lines.Add(' GetString: ' + GetString(s));
end;
procedure TForm1.btnTestAddClick(Sender: TObject);
var
s: widestring;
begin
s := widestring('1234567890');
Memo1.Lines.Add(' AddToString: ' + AddToString('1234567890'));
end;
D7 実行可能ファイルをホスト アプリとして使用して dll をデバッグし、どちらの側からでも実行できます。デバッガーでパラメーターと戻り値を調べると、上記の結果が得られます。
厄介なことに、delphi7 でインポートを文字列として宣言すると、正しい長さで無効なデータが得られます。示されているように宣言すると、返そうとすると、有効なデータ、間違った長さ、およびアクセス違反が発生します。
すべて stdcall にしても、動作は変わりません。
明らかな解決策は、私が今必要としている機能を正確に公開する単純なラッパー関数を作成することです。私はそれを行うことができますが、上記の狡猾な方法を好みます。