【问题标题】:How do I pass arrays of struct from .NET to Delphi using unmanaged export (Robert Giesecke)?如何使用非托管导出 (Robert Giesecke) 将结构数组从 .NET 传递到 Delphi?
【发布时间】:2014-03-19 13:38:06
【问题描述】:

我刚刚询问并获得了我的问题的答案:“无法返回带有非托管导出的自定义类型实例 (Robert Giesecke)”-> can't return custom type instance with unmanaged export (Robert Giesecke) 我想知道是否(以及如何)可以使用非托管导出将结构数组从 .NET 传递到 Delphi (Robert Giesecke):

  • 一样直接返回数组

[DllExport] public static void CreateSampleInstance(out Sample[] sample)

  • 在返回的结构中使用数组成员

[DllExport] public static void CreateSampleInstance(out Sample sample)

`public struct Sample
{
   Other[] Others;
}`

我的问题是如何编写 Delphi 端以及在 .NET 中设置什么属性。

非常感谢。

【问题讨论】:

    标签: c# delphi pinvoke


    【解决方案1】:

    数组更加棘手,因为您需要更加注意分配和销毁数组的位置。最干净的方法总是在调用者处分配,将数组传递给被调用者,让它填充数组。这种方法在您的上下文中看起来像这样:

    public struct Sample
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string Name;
    }
    
    [DllExport]
    public static int func(
        [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
        Sample[] samples, 
        ref int len
    )
    {
        // len holds the length of the array on input
        // len is assigned the number of items that have been assigned values 
        // use the return value to indicate success or failure
        for (int i = 0; i < len; i++)
            samples[i].Name = "foo: " + i.ToString();
        return 0;
    }
    

    您需要指定需要在向外方向编组的数组。如果您希望以两种方式编组值,那么您将使用In, Out 而不是Out。您还需要使用MarshalAsUnmanagedType.LPArray 来指示如何编组数组。而且您确实需要指定大小参数,以便编组器知道要编组回非托管代码的项目数。

    然后在 Delphi 端,您像这样声明函数:

    type
      TSample = record
        Name: WideString;
      end;
      PSample = ^TSample;
    
    function func(samples: PSample; var len: Integer): Integer; stdcall; 
      external dllname;
    

    这样称呼它:

    var
      samples: array of TSample;
      i, len: Integer;
    ....
    len := 10;
    SetLength(samples, len);
    if func(PSample(samples), len)=0 then
      for i := 0 to len-1 do
        Writeln(samples[i].Name);
    

    更新

    作为 AlexS discovered(参见下面的 cmets),仅 .net 4 支持通过引用传递大小参数索引。在早期版本中,您需要按值传递大小参数索引。

    我选择在这里通过引用传递它的原因是允许以下协议:

    1. 调用者传递in一个指示数组有多大的值。
    2. 被调用者传递输出一个值,指示已填充多少元素。

    这在 .net 4 上运行良好,但在早期版本中,您需要为步骤 2 使用额外的参数。

    【讨论】:

    • 谢谢!我必须在这样的样本之前放一个 var:function (var samples: PSample; var len:Integer) : Integer; stdcall;
    • 对不起,但如果我严格使用你的建议,我只会在调用我的 .NET 函数后得到一个空数组。如果我在 .NET 函数的数组参数上放置一个 ref 关键字,它就可以工作!顺便说一句,我在 delphi 端创建数组,将其提供给 .NET 填充并返回给 delphi。
    • 你应该删除那个Array.Resize。让我仔细检查和测试代码。
    • 所以我删除了Array.Resize(ref samples, len); 行,但它仍然引发异常。我设法使其工作的唯一方法是在 delphi 函数中使用 var samples 参数,在 .NET 函数中使用 ref samples 参数,在 .NET 函数中使用 Array.Resize()。
    • 不,有问题。我会解决并更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 2015-11-06
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-26
    • 2013-09-02
    • 1970-01-01
    相关资源
    最近更新 更多