With the release of DataFlex 2021 we introduced the capability to compile and run your application as a 64-bit executable. While preparing your code for 64-bit compilation is often not as hard as you might fear, and there is good guidance from our DataFlex Learning Center, some developers may stumble upon the curious case of structure padding. I admit, the first time that I came across the issue, I was a bit surprised myself.
The thing is that structs that are exposed to Windows functions or custom dependencies may need slight changes to still function properly. But how do you recognize that such changes are needed? Since this is not always obvious to all developers, we have created a little tool to help you with that.
Structure padding is about aligning structs to its largest member by adding extra spaces within the struct. A lot of languages and systems do this, such as Windows, and the C/C++ compiler in Visual Studio does it by default. The latter can be switched off, which is not often done. DataFlex does not do structure padding (due to historic reasons), with the result that a struct in DataFlex memory may not exactly match the struct that Windows or the external component expects. This can lead to a runtime error or other unexpected behavior when calling the external DLL or Windows API. By the way, this issue does not apply to COM objects.
To give an example, look at the figure below. This displays the memory usage of the following struct defined in C/C++:
The largest member in the struct is 4 bytes, which means that the struct members will be aligned in chunks of 4 bytes and no struct member will exceed any chunk. The result is that the area indicated in pink is empty. So, the C/C++ compiler adds empty space in memory, in order to align percentage at the start of a 4-byte chunk of data. If you would request the size of the struct in C/C++, you would get the answer 16, not 14.
DataFlex does not add the empty space, so in DataFlex the struct would be 14 bytes. And if you pass it to the C/C++ external function, you get a mismatch. That function expects percentage to start from byte 13, but it starts from byte 11.
The above example shows a case of padding that already applies in 32-bit compilation. However, I have only very rarely seen a case where structure padding is relevant in 32-bit, and this is not a real-life example. But in 64-bit it is much more relevant! Take a look at the following real-life example:
This is the DataFlex definition of a Windows struct that can be passed to Windows functions. Many developers dont immediately see that we have a problem here in 64-bit, but not in 32-bit. Why? First, tWinPoint is an inner struct and in memory it qualifies as a pointer. In 32-bit all members are 4 bytes. But in 64-bit, both pointer and handle are 8 bytes (64-bits), while DWord is still 4 bytes. This leads to the following alignment in Windows:
So, in the Windows struct there is extra padding after the DWord. To account for this, we should make a change to the DataFlex struct, such that in memory it is equal to what the Windows function expects. We can do this by manually adding a placeholder space in DataFlex, like this:
Only in 64-bit, another 4-byte member is added after the DWord, which is accomplished by using the #IFDEF statement. The extra member does not need to be assigned a value and its name is rather irrelevant.
We have received requests to create a tool to help developers with adding the right padding at the right places. Apparently, it is not an easily acquired skill to quickly see that. So, we did.
On the left hand side you can enter one or more structs, or even paste the contents of a complete source file. After clicking the Analyze button, it inserts padding items where needed on the right hand side.
The download is a 20.0 workspace that you can compile and run. This can also be used in DataFlex 2022 (20.1).