当Delphi类型为“out PChar”时,我使用什么C#参数类型?

时间:2014-02-09 23:57:13

标签: c# interface com-interop delphi

我无法将下面的接口定义从Delphi转换为C#:

  IDCDSPFilterInterface = interface(IUnknown)
    ['{BD78EF46-1809-11D6-A458-EDAE78F1DF12}']
    // removed functions thjat are already working
    function get_FilterName(Index : integer; out Name : PChar): HRESULT; stdcall;
  end;

我已经尝试过以下方式使用StringBuilder:

[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("BD78EF46-1809-11D6-A458-EDAE78F1DF12"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDCDSPFilterInterface : IBaseFilter
{
    [PreserveSig]
    int get_FilterName(int Index, [MarshalAs(UnmanagedType.LPStr)] StringBuilder Name);
}

我尝试使用LPStr,LPWStr,它们都在字符串构建器中提供了垃圾字符,LPTStr失败并显示错误消息,指出不允许使用这种编组组合。

德里方法的定义是:

function TDCDSPFilter.get_FilterName(Index : integer; out Name : PChar): HRESULT; stdcall;
begin
{$IFDEF EXCEPT_DEBUG}try{$ENDIF}
  FcsFilter.Lock;
  try
  {$IFDEF WITH_INTERNAL_DSP}
    Result := S_FALSE;
    if (Index < 0) or (Index > fFilters.Count -1) then Exit;
    Name := PChar(fFilters.Name[Index]);
    Result := S_OK;
  {$ELSE}
    Result := E_NOTIMPL;
  {$ENDIF}
  finally
    FcsFilter.UnLock;
  end;
{$IFDEF EXCEPT_DEBUG} except er('TDCDSPFilter.get_FilterName'); end; {$ENDIF}
end;

fFilters.Name声明为:

property Name[Index: integer]: String read GetName;

我的所有其他接口方法都适用于其他基本类型(in和ref),除了这个具有PChar输出的类型。

我得到S_OK但是StringBuilder中的字符串是垃圾......

我知道正确调用了该方法,因为如果我传递错误的索引,我会得到S_FALSE(因为定义了方法体)。

任何人都可以帮忙为Delphi中的PChar提供合适的编组吗?

2 个答案:

答案 0 :(得分:2)

这是一个设计相当糟糕的界面。这是一个COM接口,因此它应该使用COM字符串BSTR

但是,就目前而言,C#方必须将PChar作为IntPtr类型的out参数进行封送。声明应该是:

[PreserveSig]
uint get_FilterName(int Index, out IntPtr Name);

然后可以通过调用Marshal.PtrToStringAnsiMarshal.PtrToStringUni来恢复字符串,具体取决于字符串的编码。

您不能使用StringBuilder,因为这是针对调用者分配缓冲区的情况。这不会发生在这里。

正如我所说,使用COM字符串会更好。代码如下所示:

<强>的Delphi

function TDCDSPFilter.get_FilterName(Index: integer; 
    out Name : WideString): HRESULT; stdcall;

<强> C#

[PreserveSig]
uint get_FilterName(
    int Index,
    [MarshalAs(UnmanagedType.BStr)]
    out string Name
);

当然,这假设您可以修改界面。很可能你不能。在这种情况下,您会遇到out IntPtr

答案 1 :(得分:1)

尝试将IntPtr用于Name参数,然后使用Marshal.PtrToStringAnsi获取字符串的内容。

参考文献:

Marshal "char *" in C#

char* to a string in C#