如何使用非托管导出 (Robert Giesecke) 将结构数组从 .NET 传递到 Delphi? [英] How do I pass arrays of struct from .NET to Delphi using unmanaged export (Robert Giesecke)?

查看:21
本文介绍了如何使用非托管导出 (Robert Giesecke) 将结构数组从 .NET 传递到 Delphi?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚提出并获得了我的问题的答案:无法返回具有非托管导出的自定义类型实例(Robert Giesecke)"-> 无法返回带有非托管导出的自定义类型实例 (Robert Giesecke)我想知道是否(以及如何)使用非托管导出将结构数组从 .NET 传递到 Delphi (Robert Giesecke):

I have just asked and obtained an answer to my question that was : "can't return custom type instance with unmanaged export (Robert Giesecke)" -> can't return custom type instance with unmanaged export (Robert Giesecke) I wonder if (and how) it is possible to pass arrays of struct from .NET to Delphi using unmanaged export (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 端设置什么属性.

My question here is how to write the Delphi side and what attribute to set in the .NET one.

非常感谢.

推荐答案

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

Arrays are more tricky because you need to take more care over where the array is allocated and destroyed. The cleanest approach is always to allocate at the caller, pass the array to the callee to let it fill out the array. That approach would look like this in your context:

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 来指示如何编组数组.并且您确实需要指定大小参数,以便编组器知道要编组回非托管代码的项目数.

You need to specify that the array needs to be marshalled in the out direction. If you wanted values marshalled both ways then you would use In, Out instead of Out. You also need to use MarshalAs with UnmanagedType.LPArray to indicate how to marshal the array. And you do need to specify the size param so that the marshaller knows how many items to marshal back to the unmanaged code.

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

And then on the Delphi side you declare the function like this:

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 发现(请参阅下面的评论),仅 .net 4 支持通过引用传递大小参数索引. 在早期版本中,您需要按值传递大小参数索引.

As AlexS discovered (see comments below), passing the size param index by reference is only supported on .net 4. On earlier versions you need to pass the size param index by value.

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

The reason I chose to pass it by reference here is to allow for the following protocol:

  1. 调用者向传入一个值,该值指示数组的大小.
  2. 被调用者传递输出一个值,该值指示已经填充了多少元素.
  1. The caller passes in a value indicating how large the array is.
  2. The callee passes out a value indicating how many elements have been populated.

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

This works well on .net 4, but on earlier versions you would need to use an extra parameter for step 2.

这篇关于如何使用非托管导出 (Robert Giesecke) 将结构数组从 .NET 传递到 Delphi?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆