0

私はdllで定義されたクラスを持っています。このクラスをインターフェイスでエクスポートします。私はこの dll とクラスを他の Delphi プロジェクトで非常によく使用していますが、このクラスを C# で使用したいのですが、エラーを送信します。

ソース DLL:

type
  IMyDate = interface
    ['{D032F796-167D-4B0D-851D-2AEEA226646A}']
    Procedure Analyze_Date(var y:Integer; m,d:Integer); stdcall;
  end;

  TMyDate = Class(TInterfacedObject, IMyDate)
  Public
    Procedure Analyze_Date(var y:integer; m,d:Integer); stdcall;
  End;

procedure TMyDate.Analyze_Date(var y:Integer; m, d: Integer);
begin
  y:= m+d;
end;

Function MyDate:IMyDate; stdcall;
begin
  result:= TMyDate.Create;
end;

exports
  MyDate;

Delphi の例での単位の使用:

Function MyDate:IMyDate; stdcall; external 'Project11';

implementation

procedure TForm3.Button1Click(Sender: TObject);
var
  md:IMyDate;
  var y,m,d:Integer;
begin
  md:= MyDate;
  y:=10;
  m:=20;
  d:=30;
  md.Analyze_Date(y,m,d);
  showMessage(intTostr(y));
end;

C# で使用しますが、エラーが発生します。

//[Guid("D032F796-167D-4B0D-851D-2AEEA226646A")]
public interface IMyDate
{
    void Analyze_Date(ref int y, int m, int d); 
}

[DllImport(
"Project11.dll"
, EntryPoint = "MyDate"
, SetLastError = true
, CallingConvention = CallingConvention.StdCall
, CharSet = CharSet.Unicode)]
public static extern IMyDate MyDate(); 

private void button9_Click(object sender, EventArgs e)
{
  int y, m, d;
  IMyDate da;
  da = MyDate(); // get error this line
  y = 10;
  m = 20;
  d = 30;
  da.Analyze_Date(ref y, m, d);
}

アップデート

答えてくれてありがとう

インターフェイスとクラスに新しい関数を追加しますが、関数は false しか返しません

また、デルファイの私の関数と手順はstdcallであり、C#のインターフェースは正常です!!!

IMyDate = interface
['{D032F796-167D-4B0D-851D-2AEEA226646A}']
Function testing():Boolean; stdcall;
end;

TMyDate = Class(TInterfacedObject, IMyDate)
Public
Function testing():Boolean; stdcall;
End;

function TMyDate.testing(): Boolean;
begin
result:= true;
end;

c#:

[ComImport, Guid("D032F796-167D-4B0D-851D-2AEEA226646A"),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyDate
{
    bool testing();        
}

[DllImport(
      "Project11.dll"
      , EntryPoint = "CreateMyDate"//"MyDate"
      , SetLastError = true
      , CallingConvention = CallingConvention.StdCall
      , CharSet = CharSet.Unicode)]    
public static extern void CreateMyDate(out IMyDate Date); 

    Boolean b;

    b = da.testing();  //this line only return false
    if (b)
    {
        MessageBox.Show("ffff");
    }
4

1 に答える 1

5

私が最初に目にする問題は、関数の戻り値に対する Delphi のバイナリ インターフェイスが、C# (および実際には他のすべての主要な Windows コンパイラ) で使用されるものとは異なることです。

したがって、関数を使用する代わりに、outパラメーターを使用します。

procedure CreateMyDate(out Date: IMyDate); stdcall;
begin
  Date := TMyDate.Create;
end;

次に、C# では次のように関数を宣言できます。

[DllImport(@"Project11.dll")]
public static extern void CreateMyDate(out IMyDate Date); 

DllImport属性への偽のパラメーターの負荷を削除したことに注意してください。ランダムに追加していたと思います!

もう1つの問題はインターフェースです。をサポートする COM インターフェイスとして宣言する必要がありますIUnknown。このような:

[ComImport, Guid("D032F796-167D-4B0D-851D-2AEEA226646A"), 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyDate
{
    void Analyze_Date(ref int y, int m, int d); 
}

更新 1

更新された質問の最初の問題は、元の回答で取り上げられなかったものです。HRESULTC# インターフェイスが宣言されている方法は、ネイティブ関数がすべてCOM エラー コードを返すとマーシャラーが想定していることを意味します。C# メソッドに戻り値がある場合、暗黙的にパラメーターに変換されoutます。Delphi でこれを実現する簡単な方法があります。インターフェースの各メソッドを置き換えstdcallsafecall明らかにそのインターフェースの実装を置き換えます。関数の呼び出し規約を変更しないでくださいCreateMyDate

したがって、Delphi コードは次のようになります。

IMyDate = interface
  ['{D032F796-167D-4B0D-851D-2AEEA226646A}']
  Function testing():Boolean; safecall;
end;

TMyDate = Class(TInterfacedObject, IMyDate)
Public
  Function testing():Boolean; safecall;
End;

更新された質問のメソッドのもう 1 つの問題は、C#boolは 4 バイトの値としてマーシャリングしますが、DelphiBooleanは 1 バイトにすぎないことです。このエラーは実際には無害ですが、インターフェイスの両側を一致させることで問題を解決できます。例えば:

[return: MarshalAs(UnmanagedType.U1)]
bool testing();        

そして、私は上で言ったことを繰り返します。あなたのDllImport属性から偽のパラメータを削除しました。SetLastErrorコードが Win32 の最後のエラーを設定していないため、特に使用しないでください。あなたDllImportは私の答えとまったく同じでなければなりません。不必要な余分なパラメータを属性に追加して、物事を混乱させないでください。

更新 2

safecallDelphi 側では使用できないとコメントで述べています。HRESULTこれは、インターフェースの C# 側で署名変換を抑制する必要があることを意味します。で完了MethodImplOptions.PreserveSigです。C# インターフェイスの各メソッドに適用する必要があります。

[ComImport, Guid("D032F796-167D-4B0D-851D-2AEEA226646A"), 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyDate
{
    [MethodImplAttribute(MethodImplOptions.PreserveSig)]
    void Analyze_Date(ref int y, int m, int d); 

    [MethodImplAttribute(MethodImplOptions.PreserveSig)]
    [return: MarshalAs(UnmanagedType.U1)]
    bool testing();  
}

このインターフェースは、次のように宣言された Delphi インターフェースと一致します。

IMyDate = interface
  ['{D032F796-167D-4B0D-851D-2AEEA226646A}']
  procedure Analyze_Date(var y: Integer; m, d: Integer); stdcall;
  function testing(): Boolean; stdcall;
end;
于 2012-12-31T16:50:54.440 に答える