调用具有来自Delphi 7的ref String参数的C#.Net方法

时间:2014-02-18 02:10:20

标签: c# .net delphi com

修订问题:

我们使用D7来调用COM对象中的C#方法。 C#方法返回一个WideString。

当我们在Pascal代码中使用它时,.NET是否存在从我们脚下垃圾收集返回的WideString的风险?如果是这样,我们有什么替代方法可以安全地从C#COM对象返回一个字符串?

另外,我们的最终Delphi行SubMan:= nil是否正确释放COM对象?

C#代码

    [DispId(5)] 
    bool Test(int var1, ref int var2, ref string var3); 


    public bool Test(int var1, ref int var2, ref string var3) 
    { 
        bool result; 
        if (var1 == 0) 
        { 
            var2 = 0; 
            var3 = "zero"; 
            result = true; 
        } 
        else 
        { 
            var2 = -1; 
            var3 = "minus one"; 
            result = false; 
        } 
        return result; 
    } 

D7中生成的TLB的Pascal代码

function Test(     var1: Integer; 
               var var2: Integer; 
               var var3: WideString): WordBool; dispid 5;

调用COM对象的Pascal代码。风险变量是否会被GC编辑?

procedure TForm1.Button1Click(Sender: TObject);
var
  SubMan: TSubMan;
  Var1: Integer;
  Var2: Integer;
  Var3: WideString;
  FunctionResult: Boolean;
begin
  SubMan :=  COTSubMan.Create;
  Var1 := 1;
  FunctionResult :=  SubMan.Test(Var1, Var2, Var3);  
  // Will Var3 above be persistent in the code 
  // or might it be garbage collected by .NET before we can use it below or later?
  ShowMessage( BoolToStr(FunctionResult, TRUE) + 
               ' Var2 = ' + IntToStr(Var2) + 
               ' Var3 = ' + Var3);
  SubMan := nil;  // Is this the right way to release the COM object?
end;

2 个答案:

答案 0 :(得分:3)

你问题中的代码很好。 COM marshaller为您处理两个ref参数的生命周期。 GC没有危险,因为参数的语义清楚地表达出来了。在Delphi端使用的对象不是.net对象,因此不受GC的约束。

确实,GC不是因素,因为这是COM。另一方面有.net对象实现COM服务器的事实既不在这里也不在那里。 .net COM互操作层负责向您呈现有效的COM对象。

  

要确认,即使字符串最初是在C#COM对象中分配的,var3在我们的Delphi Button1Click方法中也可以安全使用吗?

是。请记住,这是COM,二进制互操作的标准。您不必过于关注细节。 FWIW,WideString是围绕COM BSTR类型的Delphi包装器。该字符串类型是UTF-16编码的字符串,引用计数,并从共享COM堆分配。最后一点很重要。 BSTR实例来自共享COM堆的事实是允许它们在一个模块中分配,并在另一个模块中解除分配。

  

SubMan := nil是释放COM对象的正确方法吗?

是的。虽然在此代码中有点无意义,因为局部变量即将离开范围,并且与nil赋值具有完全相同的效果。

答案 1 :(得分:0)

使用BSTR类型是最简单的方法,因为COM将处理内存(de)分配。

例如:

的Delphi:

function ReturnString(out TheString: WideString): Boolean; stdcall;
begin
  try
    TheString := 'Hello World';
  finally
    Result := True;
  end;
end;

C#:

[DllImport("mydll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern bool ReturnString([MarshalAs(UnmanagedType.BStr)]out string TheString);