7

64ビットC#アプリケーションで使用するために64ビットdllをコンパイルしようとしています。簡単なクラスとそれをテストするための簡単なアプリがあり、何をしようとしても失敗します。コードは次のとおりです。

デルファイ

library project1;

{$mode objfpc}{$H+}

uses
  Classes;


function Encrypt(aName:PChar):PChar;stdcall;
begin
  Result := aName;
end;


exports Encrypt;

begin
end.

C#

 [DllImport("project1.dll")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern String Encrypt([MarshalAs(UnmanagedType.LPStr)] String aName);

誰かがそれで何か悪いことを見ることができますか、そしてこれを機能させるために同じ単純なシナリオを作成することに夢中でなければ、私は私のテザーの終わりにいます!

4

1 に答える 1

11

これに伴う問題は、C#マーシャラーが一時的なメモリブロックを関数に渡すことaNameです。このメモリは、関数が戻るときに破棄されます。ただし、C#マーシャラーに、この同じメモリブロックをC#文字列にマーシャリングするように要求しています。

とにかく、ネイティブDLL関数からnullで終了する文字列を返すことはお勧めできません。いくつかのオプションがあります。

  1. StringBuilder文字列のメモリを事前に割り当てるには、C#側でを使用します。これには、何らかの方法で必要なサイズを取得する必要があります。これは、文字列を相互運用するための最も一般的な方法です。
  2. 文字列をCOMとして返すBSTRと、C#マーシャラーはマーシャリングと破棄の方法を知ってBSTRおり、COMアロケーターにアクセスしてこれを行うことができます。BSTRFreePascalでの使用については知りませんが、Delphiでは単にを使用しますWideString。また、C#マーシャラーにを返すことを通知する必要がありますBSTR

私は個人的にオプション2を好みます。ただし、1つの問題があります。それは、この質問で説明したように、コンパイラごとに関数の戻り値に異なるABIを使用することです。WideStringを相互運用機能の関数の戻り値として使用できないのはなぜですか。これを回避する簡単な方法は、関数の戻り値を使用するのではなく、パラメーターで文字列を返すことです。

コードは次のようになります。

パスカル

procedure Encrypt(Input: WideString; out Output: WideString); stdcall;
begin
  Output := Input;
end;

C#

[DllImport("project1.dll")]
public static extern void Encrypt(
    [MarshalAs(UnmanagedType.BStr)] string input;
    [MarshalAs(UnmanagedType.BStr)] out string output
);
于 2011-06-13T19:31:52.807 に答える