2

几天我无法解决我的问题。我在 C# 中有接口和类,它们作为 COM 服务器可见。我有需要访问此界面的 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^ (通过指针获取实例)上抛出 ACCESS VIOLATION 异常。指针 Res 不为空。它大约是 60 000 000。基本上它是内核空间区域。

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;

德尔福版本:德尔福XE2

4

2 回答 2

4

我相信CreateNew回报IProcPreviewEndArgs而不是^IProcPreviewEndArgs。所以你的代码应该是:

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

如果我是你,我会声明那些Integer映射到 C# 的返回值,IntPtr就像Pointer在 Delphi 中一样。这样,如果您编译 64 位版本,您的代码就可以工作。

我还考虑使用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;

我也想知道为什么你必须返回无类型的指针,例如,CreateNew. 为什么不能声明该函数IProcPreviewEndArgs在双方都返回?

于 2012-09-03T20:27:57.123 回答
1

Delphi 完全支持 COM/ActiveX,无论指针来自何处。

问:您使用的是什么版本的 Delphi?

建议:

1) 创建一个 C# 测试客户端来测试您的 ProcPreviewEndArgs.CreateNew() 方法。看看它是否有效。

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 回答