I’m working with Windows API and have to recreate a structure inside a Delphi record. I think I have it down, but this one was a little confusing and I need to make sure I did this right.
Here’s the original C++ structure:
typedef struct RETRIEVAL_POINTERS_BUFFER {
DWORD ExtentCount;
LARGE_INTEGER StartingVcn;
struct {
LARGE_INTEGER NextVcn;
LARGE_INTEGER Lcn;
} Extents[1];
} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER;
Notice that there’s an array struct within this struct. This is where I got lost. If I’m not mistaken, the Delphi version should look like this:
TExtent = record
NextVcn: Integer;
Lcn: Integer;
end;
TExtents = array of TExtent;
PRETRIEVAL_POINTERS_BUFFER = ^TRETRIEVAL_POINTERS_BUFFER;
TRETRIEVAL_POINTERS_BUFFER = record
ExtentCount: DWORD;
StartingVcn: Integer;
Extents: TExtents;
end;
When I use this structure in the Windows API, it does appear to work. But, because of this structure array inside of the structure, I’m a little hesitant that I did this correctly. Does this look right?
The
Extentsfield is a variable length array inlined in a struct. The actual struct will haveExtentCountelements. You cannot use a Delphi dynamic array here. In fact you can never use a Delphi dynamic array in interop.So, declare it as
array [0..0]just as the C code does. In order to access it you’ll need to disable range checking. An actual instance of this record will have valid data in indices0..ExtentCount-1.For your integral types, map
DWORDin C toDWORDin Delphi. AndLARGE_INTEGERin C toLARGE_INTEGERin Delphi. Neither of those are the same as DelphiInteger. The former is unsigned, and the latter is 64 bits wide.The
LARGE_INTEGERtype is rather awkward to work with. You may prefer to declare those fields asInt64instead.This type of struct is invariably heap allocated. The heap allocation code has to work out the size needed to fit
ElementCountitems in the variable length array. If you are allocating the buffer then you’ll need the inner record in a separately defined type so that you can conveniently name it to pass toSizeOf. If the API allocates then you are fine as above.