To continue with this content, please log in with your Data Access ID or create a new account.
Cancel Data Access ID
You may not be authorized to see this content. Please contact Data Access Europe for more information.
Cancel Data Access Europe
You are not authorized to see this content.
Cancel Data Access Europe
Next lesson:
Com Class Generator
Cancel

Migrating to DataFlex 2021, Part 3

Lesson 15 – Structure Padding


Previous lessons in this course discussed making changes to external_function definitions. This lesson goes into one specific aspect of that, which is “structure padding.” It’s important to know what it is, and how to recognize that changes to structs need to be made when preparing for 64-bit.

Structure padding is not a completely new issue, but with 64-bit it becomes much more relevant. This is because Windows’ functions, and most third party dependencies (ex: written in C or C-sharp), apply structure padding within structs, also called structure alignment. Dataflex does not do that.

What is structure padding? In C/C++ or others, structs can contain extra empty space. This is for efficiency reasons (note: does increase the size of the struct). 

Example:


This Windows struct has two integers, each 4 bytes, then two char items, each 1 byte and finally a float, which is 4 bytes. The expectation is for the struct size to be 14 bytes in total, but it will actually be 16 bytes. Items in structs are grouped and allotted a chunk of bytes. The size of the chunk is determined by the size of the largest struct member in order to align the data. In this example, the size is 4 bytes, since the integer is the largest member. ‘Id1’ and ‘Id2’ each have their own 4-byte chunk. Then there are two bytes for the chars ‘name’ and ‘c,’ but the next item is 4 bytes, and that does not fit in the remaining space of the chunk. It therefore has to start at the beginning of a new chunk of 4 bytes. Two bytes are skipped, these are empty. Here is another example. This struct has the same data but is less efficiently defined. There are two empty spaces of 3 bytes each. The size of this struct is 20 bytes.


Why is structure padding more relevant in 64-bit? This is because of structs that contain Pointers and platform dependent integer types. These set the chunk size to 8 bytes in 64-bit, whereas it was 4 bytes in 32-bit. Take this example:

In 32-bit, all struct members are 4 bytes, so the chunk size is 4 bytes and there is no added empty space. In a 64-bit compilation, the chuck size is 8 bytes because of the Pointer and LParam members. It would result in the following memory usage. Notice the two times 4 bytes of empty space. As previously mentioned, DataFlex does not do structure padding, so there are no empty spaces in DataFlex structs.


Now, when structs are defined in DataFlex that will be passed via the external_function, the memory alignment must be made to be equal to what is expected on the other side. This means that extra spaces may need to be added manually. 

DEMONSTRATION

  • This is a struct definition for the Windows’ Struct TbButtonInfo. In 32-bit this struct is correct. In 64-bit it is not, and it must be corrected for structure padding. The largest chunk size is 8 bytes when compiling 64-bit, because there are Pointer types.
  • The UInteger and the DWord make up one chunk of 8 bytes. Then two integers together also are 8 bytes. Then there is 1 byte, 1 byte and 2 bytes, and next is a Longptr type of 8 bytes. Therefore, lParam does not fit in the previous chuck and a new chunk starts here, so there is 4 bytes of empty space in between that needs to be corrected for when passing the struct to the Windows API. To solve this, add a placeholder member of 4 bytes, but only in 64-bit compilation. After lParam there is a pointer of 8 bytes and finally a 4-byte integer. To make it completely correct, another placeholder should be added at the end. This is relevant when using an array of this struct.
  • This is how applications should be corrected for structure padding in 64-bit. Crashes and unexpected behaviors can result if this is not done correctly. Included packages, such as tWinstructs.pkg, have already been adapted, and can be used as examples.
  • While structure padding may be required for accessing 64-bit external DLLs, this is not the case for COM objects, since these are packed into a COM variant of type VT_RECORD.