Migrating to DataFlex 2021 Part 1
Lesson 4: Essential changes for migration to DataFlex 2021
This lesson will focus on the minimum actions needed to complete Step 5 of the migration process; Make the essential migration changes to get it running in DataFlex 2021. Even if an application is not be converted to 64-bit or to support Unicode, there are six types of changes that may need to be made.
- Conversions between Handle array and Integer array.
- In general, two arrays of different data types cannot be converted from one to another. The handle datatype has changed from being a replacement for Integer to being a replacement for the new Longptr datatype. Longptr will be addressed further in Part 3 of this course. In earlier DataFlex versions a conversion between a handle array and an integer array was not a conversion; now it is, and it is not allowed. Doing so will lead to a runtime error.
- In this example, the function WindowHandles is called and the resulting array is stored into the iHandles array. That function will return a Handle array, which does not correspond to the integer array iHandles. It will compile fine, but when it is run an error will be generated: Illegal datatype conversion. This would not have been an issue in Dataflex 19.1, but it is in 2021. To correct this, change the datatype iHandles to a handle array.
- Dword has become UInteger
- Historically, DWord has always been a signed integer in DataFlex even though the opposite is true in other programming languages. This has been corrected in DataFlex 2021. Now Dword variables can never be negative.
- In this example, the -1 value is assigned to a DWord, but doing so convert it to the unsigned equivalent of its binary, or hexadecimal, value. The value is wrapped. An out of range error will not happen if the wrapped value fits. On this line the value is also wrapped. One effect of this is that testing a DWord on a value below zero no longer makes sense. This if statement will never be true in Dataflex 2021, so the -1 value should no longer be assigned as a kind of initialization value to a Dword variable. Look for code that does this in the application.
- TYPE Structures
- TYPE structures are not Unicode safe, not even when there are no strings in the structure. This is because TYPE structures are actually strings and are treated by the runtime as strings. But now they are UTF-8, this can lead to unexpected behavior when combinations of bytes lead to an invalid character. TYPE structures are obsolete, and will have to be replaced with Structs in DataFlex 2021.
- In this example, a TYPE structure with four DWord members is shown.
To change this, first define it as a ‘Struct’ instead of TYPE. Next, create an instance for this struct.
The String sRect is no longer needed. Remove the ZeroType command. Get Address is an obsolete command. It is recommended that it be replaced it with the AddressOf function. The address of the struct should be retrieved not the address of sRect. Replace GetBuff commands with ‘Move Rect.top to iTop’ and so on for the others.
- Rewrite conversions between String and Pointer
- Conversions between String and Pointer are no longer allowed. In previous versions of DataFlex there was special behavior when moving a strings to an address and reverse. This made a copy of the string. This behavior has been removed due to runtime changes related to the pointer type.
- In this example, the special string to pointer behavior is shown that can no longer be used. When complied, two errors result.
The first one is where the string was to be copied to another pointer location. The Memcopy function should be used instead.
- Note that the Length function should not be used to get the number of bytes of the string, because one character does not always equals one byte anymore. Instead, use the new SizeOfString function. The same should be done at the Alloc call.
- The second compile error did a copy the other way around. Use the new PointerToString function here, as the compile error suggests.
- There will still be something wrong if it is run at this point. There is an illegal datatype conversion error. Selecting to ‘Debug’ it shows that there is another pointer that it tried to convert to a string. In this case, PointerToString must be used.
- This functionality is rare, so it is not likely that this will be a common issue. Do note, however, that the compiler will not catch every issue.
- Replace ToOem and ToAnsi by Utf8ToOem and Utf8ToAnsi
- Unicode-related compiler warnings will need to be addressed. In the next lesson, the compiler warning system will be discussed in detail. For now, the most frequent compiler warnings are ToOem and ToAnsi. These functions mean: Convert FromAnsiToOEM and FromOemToAnsi respectively. The DataFlex strings are not OEM anymore, they are UTF-8. The original function have not been changed because conversions between OEM and ANSI might still be useful. Four new functions have been created: Utf8ToOEN, Utf8ToAnsi, OEMToUtf8 or AnsiToUtf8. Code will likely have to be changed to use them, or the conversion can be removed if a Unicode version of the external function is called.
- In this example, the code is compiled resulting in a number of warnings. An instance is shown using ToAnsi, which means from OEM to Ansi. DataFlex strings are OEM, however, they are UTF-8. Therefore, Utf8ToAnsi needs to be used.
- Another warning is about ToOem. This should be AnsiToUtf8 because it should be converted to DataFlex string not to OEM.
- This will not work for Unicode characters because the ANSI version of the external function is called. If an external fuction has a UTF-8 Unicode version, the code becomes simpler because the conversions between ANSI and UTF-8 are no longer needed. This external_function is actually UTF-16 not UTF-8. In Part 2 of this series, in lesson 9, the code will be shown for how to call the UTF-16 Wide version instead of the ANSI version.
- Do not pass binary data using strings
- Strings can no longer be used for binary data. Before Dataflex 2021, is was possible to put binary data into a string and then pass that string for passing the data. Now, pass a pointer to the data instead.