I’m building a DLL in Delphi, and it needs to work similar to how the Windows API works. This DLL only has one exported function…
function DoSomething(var MyRecord: TMyRecord): Integer; stdcall;
…where TMyRecord = my record I will need to re-create in C#. If I’m not mistaken, this is exactly how the standard Windows API works. This record also contains a reference to another record type…
TMyOtherRecord = record
SomeDC: HDC;
SomeOtherInt: Integer;
end;
TMyRecord = record
SomeInteger: Integer;
SomeColor: TColor;
SomeText: PChar;
SomeTextSize: Integer;
MyOtherRecord: TMyOtherRecord;
end;
Question part 1:
I’d like to see if I can avoid using PChar, if at all possible. I don’t expect anything over 255 characters to be passed through. Is there another type I can use instead which won’t require me to use a size of string?
Question part 2:
I need to double check that I am declaring this C# struct class correctly, because it needs to perfectly match the Record declared in Delphi…
public struct MyOtherRecord
{
public IntPtr SomeDC;
public int SomeOtherInt;
}
public struct MyRecord
{
public int SomeInteger;
public Color SomeColor;
public string SomeText;
public int SomeTextSize;
public MyOtherRecord OtherReord = new MyOtherRecord();
}
Question part 3:
Is it safe in this case to have a record inside of a record (or struct inside of a struct)? Pretty sure it is, but I need to make sure.
I’m going to assume that the information is flowing from C# to Delphi and not the other way, largely because that makes life a lot easier when writing the answer, and you didn’t state otherwise!
In that case the Delphi function declaration should be:
The first point is that you can’t expect
System.Drawing.Colorto be handled by the P/invoke marshaller. Declare the color asintand useColorTranslator.ToWin32andColorTranslator.FromWin32to handle the conversion.There’s nothing to be afraid of with
PChar. You don’t need a field with the string length since the length is implicit in aPChardue to the null-terminator. Just declare the field asstringin the C# struct,PCharin the Delphi record and let the P/invoke marshaller do its magic. Don’t try to write to thePCharcontent from Delphi. That will end in tears. If you want to pass a string back to the C# code then there are ways, but I won’t address them here.It’s perfectly fine to have inline structs. Nothing to worry about there. Don’t allocate them with
new. Just treat them as value types (which they are) likeint,doubleetc.In due course you will need to add
StructLayoutattributes and so on, declare your DLL function withDllImportand so on.To summarise, I would declare your structs like this:
Delphi
C#
I’ve not marked the
stringwith aMarshalAssince the default is to marshal it as aLPSTRwhich is the same as a Delphi 7PChar.I’ve only compiled this in my head so there may be a few wrinkles.