Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert structure from C to Delphi

I'm converting a C header for a unit of delphi. I'm having doubts about the UNION. For example, in the examples below, what is the logic applied in (CASE INTEGER OF)? Is this the correct way to convert this structure?

In C

typedef union _FLT_PARAMETERS {

    struct {
        PIO_SECURITY_CONTEXT SecurityContext;
        ULONG Options;
        USHORT POINTER_ALIGNMENT FileAttributes;
        USHORT ShareAccess;
        ULONG POINTER_ALIGNMENT EaLength;
        PVOID EaBuffer;                
        LARGE_INTEGER AllocationSize;  
    } Create;

    struct {
        PIO_SECURITY_CONTEXT SecurityContext;
        ULONG Options;
        USHORT POINTER_ALIGNMENT Reserved;
        USHORT ShareAccess;
        PVOID Parameters; // PNAMED_PIPE_CREATE_PARAMETERS
    } CreatePipe;

    ...

In Delphi

   TCreate = record
        SecurityContext: PIO_SECURITY_CONTEXT;
        Options: ULONG;
        FileAttributes: USHORT;
        ShareAccess: USHORT;
        EaLength: ULONG;
        EaBuffer: PVOID;                 
        AllocationSize: LARGE_INTEGER; 
   end;

   TCreatePipe = Record
        SecurityContext: PIO_SECURITY_CONTEXT;
        Options: ULONG;
        Reserved: USHORT;
        ShareAccess: USHORT;
        Parameters: PVOID; 
   end;    

   _FLT_PARAMETERS = Record
     case integer of
       0: (Create: TCreate); 
       1: (CreatePipe: TCreatePipe):
   ...
like image 571
Flz Avatar asked May 09 '14 15:05

Flz


1 Answers

Is this the correct way to convert this structure?

The union is correctly translated. Your Pascal variant record is the correct way to handle the union. The variant part of a record is treated identically to a C union. From the documentation:

Records with variant parts are complicated syntactically but deceptively simple semantically. The variant part of a record contains several variants which share the same space in memory. You can read or write to any field of any variant at any time; but if you write to a field in one variant and then to a field in another variant, you may be overwriting your own data.


The only issue I can see with your code is the macro POINTER_ALIGNMENT. What does that macro expand to? My expectation is that it will expand to __declspec(align(4)) for 32 bit code and __declspec(align(8)) for 64 bit code.

Assuming that guess is correct, your Delphi code will already have the correct layout when compiling for 32 bit. That's because each field marked with POINTER_ALIGNMENT will already be placed on a 4 byte boundary.

But the record will not be laid out correctly for 64 bit. If you are targeting 64 bit you'll have to add some extra padding because every member marked with POINTER_ALIGNMENT will be laid out incorrectly. Unfortunately there is no equivalent in Delphi to __declspec(align(#)) so you would need to add the padding manually.

If you do need to add this padding you should check very carefully that both C and Delphi versions have the same layout. Check that the offsets for each field match.

like image 110
David Heffernan Avatar answered Sep 19 '22 18:09

David Heffernan