2

数日、問題を解決するための解決策を見つけることができません。COMサーバーとして表示されるC#のインターフェイスとクラスがあります。そして、このインターフェイスにアクセスする必要があるDelphiアプリケーションがあります。しかし、私の場合、C#側で32ビットポインターをインターフェイスに返す必要があり、Delphi側でポインターをインターフェイスに変換する必要があります。何が行われますか?c#側。すべての属性は適切に記述されており、元のクラスがはるかに大きいため、ソースコードはカットされていますが、アイデアは理解できます。

[ComVisible(true)]
[CLSCompliant(true)]
[Guid("C1A57BD0-AAA2-4AB8-BA2F-ADFA04275AD5")]
[ClassInterface(ClassInterfaceType.None),
 ComSourceInterfaces(typeof(IProcPreviewEndArgs))]
public class ProcPreviewEndArgs : IProcPreviewEndArgs
{

   [ComVisible(true), PreserveSig]
   public IntPtr CreateNew()
   {
       var obj = new ProcPreviewEndArgs();
       GC.SuppressFinalize(obj);
       return Marshal.GetComInterfaceForObject(obj, typeof (IProcPreviewEndArgs));
   }
}

デルフィ側:

type
  PIProcPreviewEndArgs = ^IProcPreviewEndArgs;

 Index, Res: Integer;
 ppa : IProcPreviewEndArgs;
 pppa : PIProcPreviewEndArgs;

  ppa := CoProcPreviewEndArgs.Create;   // Creates COM object via Delphi services
  ppa.CreateNew(Res);                   // Creates object of the same type, returns as Ret (Integer)
  pppa := PIProcPreviewEndArgs(Res);    // Trying to cast Intereger to interface
  pppa^.CreateNew(Res); // just to test calling posibility

pppa ^(ポインタによるインスタンスの取得)では、ACCESSVIOLATION例外がスローされます。ポインタResはnullではありません。約600000です。基本的にはカーネル空間領域です。

UPD

[CLSCompliant(true), ComVisible(true),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 Guid("10572D64-B612-468F-86B3-D12F0B6E3CD2")]
public interface IProcPreviewEndArgs
{
    IntPtr CreateNew();
    IntPtr Get(int aMin, int aMax, uint cMin, uint cMax);
    void ToAngle(int x, int y, int w, int h, out int nx, out int ny, out int nw, out int nh);
    IntPtr GetImage();
}

Delphi(Delphiによって生成され、標準のDelphiメソッドを使用してCOMオブジェクトを操作するときにうまく機能します):

 IProcPreviewEndArgs = interface(IUnknown)
    ['{10572D64-B612-468F-86B3-D12F0B6E3CD2}']
    function CreateNew(out pRetVal: Integer): HResult; stdcall;
    function Get(aMin: Integer; aMax: Integer; cMin: LongWord; cMax: LongWord; out pRetVal: Integer): HResult; stdcall;
    function ToAngle(x: Integer; y: Integer; w: Integer; h: Integer; out nx: Integer; 
                     out ny: Integer; out nw: Integer; out nh: Integer): HResult; stdcall;
    function GetImage(out pRetVal: Integer): HResult; stdcall;
  end;

Delphiバージョン:Delphi XE2

4

2 に答える 2

4

私はそれがではなくCreateNew戻ると信じています。したがって、コードは次のようになります。IProcPreviewEndArgs^IProcPreviewEndArgs

var
  ppa1, ppa2: IProcPreviewEndArgs;
....
ppa1 := CoProcPreviewEndArgs.Create;   
ppa1.CreateNew(Res);                   
ppa2 := IProcPreviewEndArgs(Res);    
ppa2.CreateNew(Res); 

もし私があなたなら、DelphiのようIntegerにC#にマップする戻り値を宣言します。そうすれば、64ビットバージョンをコンパイルした場合でもコードが機能します。IntPtrPointer

safecallまた、ではなくを使用することも検討してstdcallいるので、コンパイラにエラーHRESULTをDelphi例外に変換させます。

IProcPreviewEndArgs = interface(IUnknown)
  ['{10572D64-B612-468F-86B3-D12F0B6E3CD2}']
  function CreateNew: Pointer; safecall;
  function Get(aMin: Integer; aMax: Integer; cMin: LongWord; cMax: LongWord): Pointer; safecall
  procedure ToAngle(x: Integer; y: Integer; w: Integer; h: Integer; out nx: Integer; 
                    out ny: Integer; out nw: Integer; out nh: Integer); safecall;
  function GetImage: Pointer; safecall;
end;

また、たとえば、で型指定されていないポインタを返さなければならないのも不思議ですCreateNewIProcPreviewEndArgsその関数が両側に戻ることを宣言できないのはなぜですか?

于 2012-09-03T20:27:57.123 に答える
1

Delphiは、ポインタがどこから来ているかに関係なく、COM/ActiveXを完全にサポートしています。

Q:どのバージョンのDelphiを使用していますか?

提案:

1)ProcPreviewEndArgs.CreateNew()メソッドをテストするためのC#テストクライアントを作成します。それが機能するかどうかを確認します。

2)この記事を確認します。

  • http://delphi.about.com/library/weekly/aa121404a.htm

    (Delphiポインタではなく)COM/ActiveXクラスとGUIDSを使用するようにDelphiコードを変更します。手順1で作業したC#テストクライアントと同じように動作させます。COM/ ActiveXの使用を開始する前に、Delphi .exeのどこかでCoInitialize()を呼び出すなど、すべての「基本」を実行していることを確認してください。

3)COM/ActiveXが必要かどうかを検討してください。おそらく、あなたのデザインはCOM / ActiveXなしでPInvokeを使用できますか?

于 2012-09-03T20:08:52.883 に答える