Migration examples

Modifying the parameter data type

In order to improve product security, the compiler has been upgraded from Visual Studio 2010 to Visual Studio 2022. 64-bit programs in Visual Studio 2010 will basically not use the upper 32 bits which Visual Studio 2022 will use. This change will cause the definition of external functions that can be called by 64-bit programs in PowerBuilder 2019 fails to be called in PowerBuilder 2022 and later. This section will show you how to modify the definition parameter type to avoid this type of problem.

For example, in the following scenario, we will need to modify the data type of the parameter or return value to LongPtr in the external function.

#1: The original PowerBuilder API is defined as Long/uLong Integer type, the interface prototype is defined as a pointer type parameter or return value.

#2: The original PowerBuilder API is defined as Long/uLong Integer type, the interface prototype definition type is a 64-bit data type parameter or return value.

#3: The type defined in the interface prototype is the Handle type.

Here is a code example:

32-bit DLL function reference definition

FUNCTION    uLong      RegisterEventSource ( uLong lpUNCServerName, string lpSourceName ) Library "ADVAPI32.dll" Alias For "RegisterEventSourceW"

64-bit DLL function definitions, compatible with 32/64 bits

FUNCTION    Longptr    RegisterEventSource ( Longptr lpUNCServerName, string lpSourceName ) Library "ADVAPI32.dll" Alias For "RegisterEventSourceW"

PowerScript

String                    ls_message_source
Longptr                   lul_event_handler
lul_event_handler = RegisterEventSource (0, ls_message_source )

Areas to modify:

a. The RegisterEventSource API function prototype can be found on the Microsoft official website and the return value type is HANDLE, as shown below. Therefore, the return value type must be modified to Longptr.

b. The lpUNCServerName parameter ​is an LPCSTR pointer type, as shown below, therefore, the type must be modified to Longptr.

c. The lul_event_handler variable for the interface return value must be defined as Longptr type.

Determining the structure size

When calling the Windows API interface in PowerBuilder, if the interface contains a structure, you will need to calculate the size of the structure and define the structure in PowerBuilder.

For example, ChooseFont () in Windows

Declaration:

Function boolean ChooseFont ( &Ref CHOOSEFONT lpcf ) Library "comdlg32.dll" Alias For "ChooseFontA;Ansi"

Structure CHOOSEFONT:

typedef struct tagCHOOSEFONTA {
   DWORD           lStructSize;
   HWND            hwndOwner;          // caller's window handle
   HDC             hDC;                // printer DC/IC or NULL
   LPLOGFONTA      lpLogFont;          // ptr. to a LOGFONT struct
   INT             iPointSize;         // 10 * size in points of selected font
   DWORD           Flags;              // enum. type flags
   COLORREF        rgbColors;          // returned text color
   LPARAM          lCustData;          // data passed to hook fn.
   LPCFHOOKPROC    lpfnHook;           // ptr. to hook function
   LPCSTR          lpTemplateName;     // custom template name
   HINSTANCE       hInstance;          // instance handle of.EXE that
                                       //   contains cust. dlg. template
   LPSTR           lpszStyle;          // return the style field here
                                       // must be LF_FACESIZE or bigger
   WORD            nFontType;          // same value reported to the EnumFonts
                                       //   call back with the extra FONTTYPE_
                                       //   bits added
   WORD            ___MISSING_ALIGNMENT__;
   INT             nSizeMin;           // minimum pt size allowed &
   INT             nSizeMax;           // max pt size allowed if
                                       //   CF_LIMITSIZE is used
} CHOOSEFONTA;

Since the first parameter lStructSize needs to obtain the size of the structure, it is necessary to calculate the size of the structure first. In C++, the sizes of 32-bit and 64-bit program pointers are different, resulting in different sizes of structures.

The size of the above 32-bit structure is 60. The details are as follows:

   DWORD           lStructSize;        4
   HWND            hwndOwner;          4
   HDC             hDC;                4
   LPLOGFONTA      lpLogFont;          4
   INT             iPointSize;         4
   DWORD           Flags;              4
   COLORREF        rgbColors;          4
   LPARAM          lCustData;          4
   LPCFHOOKPROC    lpfnHook;           4
   LPCSTR          lpTemplateName;     4
   HINSTANCE       hInstance;          4
                                       
   LPSTR           lpszStyle;          4
                                       
   WORD            nFontType;          2
                                                                              //   bits added
   WORD            ___MISSING_ALIGNMENT__;  2
   INT             nSizeMin;           4
   INT             nSizeMax;           4

The size of the 64-bit structure is different between the 8-byte alignment and the 1-byte alignment. For 8-byte alignment, the size is 104, and for 1-byte alignment, the size is 92.

   DWORD           lStructSize;        4
   HWND            hwndOwner;          8
   HDC             hDC;                8
   LPLOGFONTA      lpLogFont;          8
   INT             iPointSize;         4
   DWORD           Flags;              4
   COLORREF        rgbColors;          4
   LPARAM          lCustData;          8
   LPCFHOOKPROC    lpfnHook;           8
   LPCSTR          lpTemplateName;     8
   HINSTANCE       hInstance;          8
                                       
   LPSTR           lpszStyle;          8
                                       
   WORD            nFontType;          2
                                                                              //   bits added
   WORD            ___MISSING_ALIGNMENT__;  2
   INT             nSizeMin;           4
   INT             nSizeMax;           4

In PowerBuilder 12.6 and later, the default byte alignment is 8-byte alignment, therefore, the structure field lStructSize needs to be entered 104 in 64-bit systems.

PowerBuilder code example that is compatible with 32/64-bit DLL instance:

Structure definition:

DLL function reference definition:

Function boolean ChooseFont (Ref CHOOSEFONT lpcf ) Library "comdlg32.dll" Alias For "ChooseFontA;Ansi"

Before modification:

// initialize the structure further
lstr_ChooseFont.lstructsize = 60
lstr_ChooseFont.hwnd = Handle(aw_parent)
lstr_ChooseFont.flags = CF_SCREENFONTS+CF_INITTOLOGFONTSTRUCT+CF_EFFECTS

If Not ChooseFont(lstr_ChooseFont) Then
 GlobalUnlock(ll_LogFont)
 GlobalFree(ll_LogFont)
 Return False
End If

After modification:

environment env

// initialize the structure further
// determine whether the current app is 32 or 64-bit
ll_return = GetEnvironment ( env )
IF ll_return <> 1 THEN RETURN false
CHOOSE CASE env.ProcessBitness
CASE 32
 lstr_ChooseFont.lstructsize = 60
CASE 64
 lstr_ChooseFont.lstructsize = 104
CASE ELSE
    RETURN false
END CHOOSE
lstr_ChooseFont.hwnd = Handle(aw_parent)
lstr_ChooseFont.flags = CF_SCREENFONTS+CF_INITTOLOGFONTSTRUCT+CF_EFFECTS

// call the dialog
If Not ChooseFont(lstr_ChooseFont) Then
 GlobalUnlock(ll_LogFont)
 GlobalFree(ll_LogFont)
 Return False
End If

Methods for identifying C++ 64-bit data types

In the previous sections, a few examples are given to help explain modifying the data type to be 64-bit compatible, however, in actual usage, it is much more complicated to identify the data type in the interface. This section will guide you on how to locate interface prototype and identify data types.

For more information on how to identify the C++ 64-bit data type, refer to

https://docs.microsoft.com/en-us/windows/win32/winprog64/programming-guide-for-64-bit-windows

https://docs.microsoft.com/en-us/cpp/build/common-visual-cpp-64-bit-migration-issues?view=msvc-170

C++ ILP32 and LP64 data model

The 32-bit environment involves the "ILP32" data model because the C data types are 32-bit int, long, and pointers. The 64-bit environment uses a different data model. At this time, long and pointers are 64-bit, so it is called the "LP64" data model. The following table lists common type size comparisons (this table is ultimately subject to the official version and is just a reference table when writing examples).

From the above table, we can see that the porting work from 32-bit to 64-bit is mainly to deal with various problems caused by length changes. Many correct operations on 32-bit platforms no longer hold true on 64-bit platforms.

Looking for DLL interface prototype

Generally, a C++ library file will be accompanied by a header file, as shown below. When you open this fml.h file, it will generally contain the definition prototype of the interface; we can analyze and confirm whether the parameter type is a 64-bit data type based on the interface prototype.

Looking for base types for common extension types in C++

As shown in the figure below, create a new C++ project, enter an extended type: DWORD, and then press F12, it will jump to the definition of the type. The original definition type of DWORD is Unsigned long in a 64-bit program. It is a 64-bit data type.