【问题标题】:Passing array of struct from c# to delphi将结构数组从 c# 传递给 delphi
【发布时间】:2014-07-08 07:50:06
【问题描述】:

我在 VS2010 中使用 Robert Giesecke Unmanaged Exports 1.2.6,我的目标是从 c# (.NET 3.5) 到 delphi (D7)。 我不得不承认,我对 delphi 不是很熟悉。

我已经阅读了this post,但建议的答案对我不起作用: 在 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 窗口,如果我继续,应用程序将退出,不会出现异常或错误消息。 如果我在不使用 dbugger 的情况下运行它,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

【问题讨论】:

  • 使用调试器运行。听起来像加载时间链接失败。如果链接成功,您就可以进入该程序。代码确实有效。
  • @DavidHeffernan 我能够进入程序并且正在运行调试器。调试器在调用 func() 时打开 CPU 窗口。 for 循环不再执行。 C#函数内的控制台输出完成,因此dll被链接并执行。
  • @DavidHeffernan 您使用的是什么 .NET、delphi 和 UnmanagedExport 版本?
  • 我现在什么都没用。那个Q来自过去。我暂时看不到这个。
  • @DavidHeffernan 仅供参考:我发现了这个问题。这是关于 .NET 版本的。请看下面我的回答。无论如何,感谢您的帮助!

标签: c# delphi pinvoke


【解决方案1】:

好像我发现了问题:

如果使用 .NET 4.0 或更高版本,代码运行良好。如果您使用 .NET 3.5 或更低版本,则必须按值传递 len 参数。

请参阅 MSDN 文档SizeParamIndex v3.5

包含大小的参数必须是一个按值传递的整数。

请参阅 MSDN 文档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 here 发布的代码仅适用于 .NET >= 4.0! 如果您必须使用 .NET

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    相关资源
    最近更新 更多