C#调用Delphi DLL返回结构内的结构

时间:2011-11-23 21:19:09

标签: c# delphi pinvoke

另一个德尔福互操作问题......

我有这个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的控制台输出始终是枚举值,即使它在Delphi代码中显然设置为2。

现在,如果我只是将TestType结构中的TestRecord结构数组改为使用简单的整数数组,那么一切都很好。

为什么整数数组不起作用,结构数组却没有?

3 个答案:

答案 0 :(得分:3)

主要问题是TTestRecord没有定义内容。 C#代码将其作为大小为1的字段进行编组.Delphi编译器将其视为大小为0.因此两个结构之间存在不匹配。 C#代码为Marshal.SizeOf(typeof(TestType))返回260,而Delphi编译器为SizeOf(TTestType)返回8。

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

请注意,@ JMarsch和@Ken White也会生成有效积分。您需要确保正确编组枚举并且struct布局匹配。由于结构的填充方式,你可能会在没有对你的枚举编组做任何事情的情况下离开,但你可能同样不幸运!

答案 1 :(得分:2)

自从我使用Delphi(如'98)以来,这已经是整整一生了,但是,我记得,Delphi中的枚举是1个字节的数字。 c#中的枚举是整数(32位)。

因此,您可以尝试将c#enum定义为

enum TestEnum: byte {One, Two}

这个问题没有解释它是如何使用int数组的。关于我能想到的唯一另一件事就是确保c#enum的值与Delphi Enum的值完全匹配(所以使用teOne,teTwo),但由于我们实际上是在谈论一个整数/字节,我不明白这有多重要。

答案 2 :(得分:2)

您需要在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}