我无法将下面的接口定义从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提供合适的编组吗?
答案 0 :(得分:2)
这是一个设计相当糟糕的界面。这是一个COM接口,因此它应该使用COM字符串BSTR
。
但是,就目前而言,C#方必须将PChar
作为IntPtr
类型的out参数进行封送。声明应该是:
[PreserveSig]
uint get_FilterName(int Index, out IntPtr Name);
然后可以通过调用Marshal.PtrToStringAnsi
或Marshal.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获取字符串的内容。
参考文献: