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结构体的数组更改为使用一个简单的整数数组,一切都很好。
为什么整型数组可以工作,而结构体数组却不行?
主要问题是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}