3

C# から dll 内で Delphi 関数を呼び出しています。ここにデルファイ関数の署名があります -

function CALinkDecode(sCode: PWideChar; SubscriberID, MailshotID, LinkID: PDWORD):
  PAnsiChar; stdcall;

そして、これが私がそれを呼んでいる方法です。

 string input = "qvoxyetvr7wksss2zbrmr";
        int cas, cam, cal;
        var errorString = CALinkDecode(input, out cas,
                                         out cam, out cal);

しかし、アプリを実行すると、この条件が Delphi 関数で true として評価されます -

if (sCode = nil) or (Length(sCode) <> 21) or (SubscriberID = nil) or (MailshotID = nil) or (LinkID = nil) then
begin
  Result := 'E_INVALIDARG';
end

関数シグネチャの正しいデータ型を渡しているかどうか、およびそれを行う正しい方法は何かを知りたいだけです。ありがとう。

4

1 に答える 1

4

当面の問題は、ANSI テキストを sCode パラメータに渡すことです。残念ながら、それを明確にする p/invoke 宣言を省略しました。

これは簡単に修正できますが、はるかに大きな問題があります。この関数は、正しく設計されていないため、呼び出すのが困難です。ヒープに割り当てられた文字列ではなく、コンパイラによって割り当てられた定数文字列を返す場合にのみ実行可能です。次の場合、その署名で強制的に動作させることができます。

  1. ネイティブ コードからデアロケータ関数をエクスポートしました。
  2. COM ヒープなどの共有ヒープを使用して文字列を割り当てます。

COM エラー コードを文字列形式で返しているようです。それはひねくれています。代わりに、HRESULT を返すことで、作業を非常に簡単にすることができます。

とにかく、直接の質問に答えるには、次のように p/invoke を宣言します。

[DllImport(@"Mylib.dll", CharSet=CharSet.Unicode)]
static extern IntPtr CALinkDecode(
    string sCode,
    out uint SubscriberID,
    out uint MailshotID,
    out uint LinkID
);

次に、このように呼び出します

IntPtr retvalptr = CALinkDecode(...);

次に、ポインターを文字列にマーシャリングします

string retval = Marshal.PtrToStringAnsi(retvalptr);

ただし、返された文字列データが静的に割り当てられている場合にのみ機能することに注意してください。そうしないと、リークが発生したり、アクセス違反が発生したりします。

私の主なアドバイスは、インターフェイスを再設計することです。エラー コードを文字列で返さないでください。

一般的に、Delphi から C# に文字列を渡す必要がある場合は、次のようにします。

  • Delphi コードで WideString 型の out パラメータを宣言します。これにより、COM BSTR がラップされます。
  • マネージ側で、string 型の out パラメータを宣言します。そのパラメーターを [MarshalAs(UnmanagedType.BStr)] で装飾します。

Delphi は戻り値に異なる ABI を使用するため、WideString の戻り値を MS ツールにマーシャリングできないことに注意してください。そのため、out パラメータを使用します。

于 2013-05-26T11:45:25.710 に答える