将struct数组从c#传递到delphi

本文关键字:delphi struct 数组 | 更新日期: 2023-09-27 18:11:49

我在VS2010中使用Robert Giesecke Unmanaged Exports 1.2.6,我的目标是传递来自c#的struct数组。delphi (D7)。我得承认,我对delphi不是很熟悉。

我已经读了这篇文章,但建议的答案不适合我:当在delphi中调用func时,cpu调试窗口打开,如果我继续,应用程序将毫无例外地退出,没有期望的结果。

下面是我试过的代码:

c#平台x86
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
namespace ArrayTest
{
    public class Class1
    {
        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;
        }
    }
}

Delphi7

program DelphiApp;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  ActiveX;
type
  TSample = record
    Name: WideString;
  end;
  PSample = ^TSample;
function func(samples: PSample; var len: Integer): Integer; stdcall;
  external 'ArrayTest.dll';
procedure Test2;
var
  samples: array of TSample;
  i, len: Integer;
begin
  len := 10;
  SetLength(samples, len);
  if func(PSample(samples), len)=0 then
    for i := 0 to len-1 do
      Writeln(samples[i].Name);
end;
begin
  Test2();
end.

如前所述,调试器打开cpu窗口,如果我继续,应用程序退出,没有异常或错误消息。如果我在没有调试器的情况下运行它,Windows告诉我应用程序不再工作并关闭应用程序。

我错过了什么?

修改代码:

[DllExport]
public static int func(
    [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    Sample[] samples,
    ref int len
)
{
    Console.WriteLine("return 0");
    return 0;
}
procedure Test2;
var
  samples: array of TSample;
  i, len: Integer;
begin
  len := 10;
  SetLength(samples, len);
  if func(PSample(samples), len)=0 then
    for i := 0 to len-1 do
      Writeln('D7: ', i);
end;

即使我不访问数组的任何一边,行为仍然是相同的。

控制台输出:return 0

将struct数组从c#传递到delphi

似乎我发现了问题:

如果使用。net 4.0或更高版本,代码运行良好。如果使用。net 3.5或更低版本,则必须通过value传递lens参数。

参见MSDN-documentation SizeParamIndex v3.5:

包含size的参数必须是一个整数,通过value传递。

参见MSDN-documentation SizeParamIndex v4.0:

当数组作为c风格数组传递时,封送处理程序不能确定数组的大小。因此,要传递一个托管数组对于非托管函数或方法,必须提供两个参数:

  • 数组,由引用或值定义。

  • 数组大小,由引用或值定义。

使用。net 3.5的代码:

c#

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

Delphi7

function func(samples: PSample; len: Integer; var outLen: Integer): Integer; stdcall;
  external 'ArrayTest.dll';
procedure Test2;
var
  samples: array of TSample;
  i, len: Integer;
begin
  len := 0;
  // query the required array size
  i := func(PSample(samples), len, len);
  if i>0 then
  begin
    len := i;
    SetLength(samples, len);
    if func(PSample(samples), len, len)>=0 then
      for i := 0 to len-1 do
        Writeln(samples[i].Name);
  end;
end;

结论:

在我的问题中发布的代码和David Heffernan在这里发布的代码只适用于。net>= 4.0!如果你必须使用。net <= 3.5,你必须通过值传递arraysize,而不是通过引用!