c#调用Delphi DLL返回结构中的结构

本文关键字:结构 返回 DLL 调用 Delphi | 更新日期: 2023-09-27 18:15:47

又一个Delphi互操作问题......

我有这个Delphi代码:
library DelphiDll;
uses
  Dialogs,
  SysUtils,
  Classes;
  type
    TestEnum = (teOne, teTwo);
    TTestRecord = record
    end;
    TTestType = record
      MyTestRecords: array [1..255] of TTestRecord;
      MyTestEnum: TestEnum;
    end;
  {$R *.res}
  function DllFunction(var testType: TTestType): Boolean stdcall; export;
  begin
    testType.MyTestEnum := teTwo;
    Result := True;
  end;
  exports DllFunction;
  begin
  end.

这个c#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DelpiDllTester
{
    public enum TestEnum
    {
        One,
        Two
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct TestType
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
        public TestRecord[] MyTestRecords;
        public TestEnum MyTestEnum;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct TestRecord
    {
    }
    class Program
    {
        [DllImport("DelphiDll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public static extern bool DllFunction(ref TestType testType);
        static void Main(string[] args)
        {
            TestType testType = new TestType();
            bool dllFunctionResult = DllFunction(ref testType);
            Console.WriteLine(dllFunctionResult);
            Console.WriteLine(testType.MyTestEnum);
            Console.ReadLine();
        }
    }
}

当我运行c#代码时,控制台输出为testType。MyTestEnum始终是枚举值1,即使它在Delphi代码中明确设置为2。

现在,如果我简单地从TestType结构体中使用TestRecord结构体的数组更改为使用一个简单的整数数组,一切都很好。

为什么整型数组可以工作,而结构体数组却不行?

c#调用Delphi DLL返回结构中的结构

主要问题是TTestRecord没有在其中定义内容。c#代码将其封送为大小为1的字段。Delphi编译器认为它的大小为0。因此,这两种结构之间存在不匹配。c#代码对Marshal.SizeOf(typeof(TestType))返回260,而Delphi编译器对SizeOf(TTestType)返回8。

在实际代码中,可能会有一些实际的内容在该记录中,当你这样做时,一切都会开始工作。

请注意@JMarsch和@Ken White也提出了有效的观点。您需要确保枚举被正确编组,并且struct布局匹配。由于结构被填充的方式,您可能不需要对枚举编组做任何操作,但您同样可能很不幸!

自从我使用Delphi(像'98)以来,这是另一个生命周期,但是,正如我所记得的,Delphi中的枚举是1字节数。c#中的枚举是int型(32位)。

因此,您可以尝试将c# enum定义为
enum TestEnum: byte {One, Two}

这里没有解释的是它是如何处理int类型数组的。关于我能想到的唯一一件事是确保c# enum的值与Delphi enum的值完全匹配(因此使用teOne, teTwo),但由于我们实际上是在讨论一个整数/字节,我不认为这有什么关系。

您需要在Delphi代码中设置枚举大小。Delphi将使它尽可能小,但是。net方面希望int。在枚举声明之前将以下内容添加到代码中:

{$MINENUMSIZE 4}   // can also use {$Z4} but it's not clear later when
                   // you're trying to maintain the code.
                   // Or you can use {$Z-} and {$Z+}, for
                   // {$Z1} and {$Z4} respectively
// Your enum declaration
{$MINENUMSIZE 1}