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 Extents
field is a variable length array inlined in a struct. The actual struct will have ExtentCount
elements. 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 indices 0..ExtentCount-1
.
For your integral types, map DWORD
in C to DWORD
in Delphi. And LARGE_INTEGER
in C to LARGE_INTEGER
in Delphi. Neither of those are the same as Delphi Integer
. The former is unsigned, and the latter is 64 bits wide.
PRetrievalPointersBuffer = ^TRetrievalPointersBuffer;
TRetrievalPointersBuffer = record
ExtentCount: DWORD;
StartingVcn: LARGE_INTEGER;
Extents: array [0..0] of record
NextVcn: LARGE_INTEGER;
Lcn: LARGE_INTEGER;
end;
end;
The LARGE_INTEGER
type is rather awkward to work with. You may prefer to declare those fields as Int64
instead.
This type of struct is invariably heap allocated. The heap allocation code has to work out the size needed to fit ElementCount
items 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 to SizeOf
. If the API allocates then you are fine as above.