Reputation: 861
Yet another Delphi interop question......
I have this Delphi code:
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.
And this C# code:
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();
}
}
}
When I run the C# code, the console output for testType.MyTestEnum is always the enum value One even though it is clearly set to Two in the Delphi code.
Now, if I simply change from using the array of TestRecord structures in the TestType structure to using a simple array of integers, all is well.
Why does the array of integers work yet the array of structures does not?
Upvotes: 2
Views: 1362
Reputation: 613232
The main problem is the fact that TTestRecord
has no contents defined in it. The C# code marshals that as a field of size 1. The Delphi compiler regards that as having size 0. And hence there is a mismatch between the two structures. The C# code returns 260 for Marshal.SizeOf(typeof(TestType))
whereas the Delphi compiler returns 8 for SizeOf(TTestType)
.
In the real code presumably there will be some actual content in that record and when you do that, everything will start to work.
Note that @JMarsch and @Ken White make valid points too. You will need to make sure that the enum is being marshalled correctly and that the struct
layouts match. Because of the way structs are padded, you may get away without doing anything to your enum marshalling, but you may equally well be unlucky!
Upvotes: 3
Reputation: 125727
You need to set the enumeration size in your Delphi code. Delphi will make it as small as possible, but the .NET side expects an int
. Add the following to your code before the enumeration declaration:
{$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}
Upvotes: 2
Reputation: 21751
It's been a whole other lifetime since I used Delphi (like '98), but, as I remember, enums in Delphi were 1 byte numbers. Enums in c# are ints (32-bit).
So, you might try defining your c# enum as an
enum TestEnum: byte {One, Two}
The thing this does not explain is how it worked with an array of int. About the only other thing I can think of is to make sure that the values of the c# enum exactly match those of the Delphi Enum (so use teOne, teTwo), but since we are really talking about an integer/byte under the covers, I don't see how that would matter.
Upvotes: 2