Code examples

Example 1:

For example, to load the runtime DLL file PBORC190.dll from where PowerBuilder IDE is installed, you write code differently between 2019 R3 and 2019 R2.

Also note that the file name PBORC190.dll in 2019 R2 has been changed to PBORC.dll in 2019 R3.

Original code in 2019 R2:

hORCALibrary = AfxLoadLibrary("PBORC190.dll"))

Modified code in 2019 R3:

This code example hard-codes the path of IDE and runtime, if you want to read the directory from the registry, use the next example.

//First, defines the AddEnvironmentPath method
BOOL AddEnvironmentPath(LPCTSTR lpAddPath)
{
   TCHAR szSysPath[1024 * 8] = { 0 };
   TCHAR szNewPath[1024 * 8] = { 0 };

   if(0 == GetEnvironmentVariable(_T("path"), szSysPath, 1024 * 8))
      return FALSE;

   _tcscpy_s(szNewPath, lpAddPath);
   _tcscat_s(szNewPath, _T(";"));
   _tcscat_s(szNewPath, szSysPath);

   if(0 == SetEnvironmentVariable(_T("path"), szNewPath))
      return FALSE;

   return TRUE;
}

//Adds the path of runtime file before loading the runtime DLL
//The path needs to be updated when PB is upgraded
AddEnvironmentPath(_T("C:\\Program Files (x86)\\Appeon\\Common\\PowerBuilder\\Runtime 19.2.0.2566"));
AddEnvironmentPath(_T("C:\\Program Files (x86)\\Appeon\\PowerBuilder 19.0\\IDE\\"));
(hORCALibrary = AfxLoadLibrary("PBORC.dll")

Or you can write code like this in 2019 R3 which reads the path of IDE and runtime from the registry instead of the hard-coded path:

//First, defines the AddEnvironmentPath method
//AddEnvironmentPath(_T("19.2.0.1080"), _T("19"));
//AddEnvironmentPath(_T("19.2.0.1080"), NULL);
BOOL AddEnvironmentPath(LPCTSTR lpRuntimeVersion, LPCTSTR lpIDEShortVersion)
{
    LONG lRet = 0;
    HKEY hkReg = NULL;
    TCHAR   szIDEPath[MAX_PATH] = { 0 };
    TCHAR   szRTPath[MAX_PATH] = { 0 };
    TCHAR   szIDEName[MAX_PATH] = { 0 };
    TCHAR   szTmpRTPath[MAX_PATH * 2] = { 0 };
    TCHAR   szTmpIDEPath[MAX_PATH * 2] = { 0 };
    TCHAR   szSysPath[1024 * 8] = { 0 };
    TCHAR   szNewPath[1024 * 8] = { 0 };
    TCHAR   szRegPath[MAX_PATH] = { 0 };
    DWORD   cbLen = MAX_PATH * sizeof(TCHAR);
    DWORD   dwType = REG_SZ;

    //Reads runtime path from registry
    if (NULL == lpRuntimeVersion)
        return FALSE;
    
    wsprintf(szRegPath, _T("%s\\%s"), _T("Software\\Sybase\\PowerBuilder Runtime"), lpRuntimeVersion);
    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, 0, KEY_QUERY_VALUE, &hkReg);
    if ((ERROR_SUCCESS != lRet) || (NULL == hkReg))
        return FALSE;
    
    lRet = RegQueryValueEx(hkReg, _T("Location"), 0, &dwType, (LPBYTE)szRTPath, &cbLen);
    RegCloseKey(hkReg);

    if (_tcslen(szRTPath) <= 0)
        return FALSE;
    
    wsprintf(szTmpRTPath, _T("%s;%s\\X64;"), szRTPath, szRTPath);

    //Reads IDE path from registry
    if (lpIDEShortVersion && _tcslen(lpIDEShortVersion) > 0)
    {
        hkReg = 0;
        wsprintf(szRegPath, _T("%s\\%s.0"), _T("Software\\Sybase\\PowerBuilder"), lpIDEShortVersion);
        lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, 0, KEY_QUERY_VALUE, &hkReg);
        if ((ERROR_SUCCESS != lRet) || (NULL == hkReg))
            return FALSE;
        
        cbLen = MAX_PATH * sizeof(TCHAR);
        lRet = RegQueryValueEx(hkReg, _T("Location"), 0, &dwType, (LPBYTE)szIDEPath, &cbLen);
        cbLen = MAX_PATH * sizeof(TCHAR);
        lRet = RegQueryValueEx(hkReg, _T("IPS Name"), 0, &dwType, (LPBYTE)szIDEName, &cbLen);
        RegCloseKey(hkReg);

        if (_tcslen(szIDEPath) <= 0 || _tcslen(szIDEName) <= 0)
            return FALSE;
        
        wsprintf(szTmpIDEPath, _T("%s\\%s\\IDE;%s\\%s\\IDE\\X64;"), szIDEPath, szIDEName, szIDEPath, szIDEName);
    }

    if (0 == GetEnvironmentVariable(_T("path"), szSysPath, 1024 * 8))
        return FALSE;

    _tcscpy_s(szNewPath, szTmpRTPath);
    _tcscat_s(szNewPath, szTmpIDEPath);
    _tcscat_s(szNewPath, szSysPath);

    if (0 == SetEnvironmentVariable(_T("path"), szNewPath))
        return FALSE;

    return TRUE;
}

In summary, you need to write code in two steps in version 2019 R3:

Step 1: Define a method that can add a path to the PATH environment variable.

Step 2: Call the method to add the PowerBuilder Runtime and PowerBuilder IDE directories to the PATH environment variable and then load the DLL file.

Note that if the path of IDE or runtime is hard-coded in the scripts, make sure to update the path accordingly if PowerBuilder Runtime and IDE are upgraded to a new version.

Example 2:

If you have source code like below which determines the PowerBuilder versions according to the class name, you will need to change the code accordingly.

Original code in 2019 R2:

Environment le_env

GetEnvironment(le_env)

//Determines position of window within microhelp bar
ii_width = st_time.x + st_time.width + 25
this.width = ii_width

//Sets object class name
choose case le_env.PBMajorRevision
       case 10, 11, 12
              choose case le_env.PBMinorRevision
                     case 5
                           is_classname = "FNHELP" + &
                                  String(le_env.PBMajorRevision) + "5"
                     case 6
                           is_classname = "FNHELP" + &
                                  String(le_env.PBMajorRevision) + "6"
                     case else
                           is_classname = "FNHELP" + String(le_env.PBMajorRevision * 10)
              end choose
       case else
              is_classname = "FNHELP" + String(le_env.PBMajorRevision * 10)
end choose

//Sets parenthood
this.wf_setparent()

Modified code in 2019 R3:

choose case le_env.PBMajorRevision
         case 10, 11, 12
                   choose case le_env.PBMinorRevision
                            case 5
                                     is_classname = "FNHELP" + &
                                               String(le_env.PBMajorRevision) + "5"
                            case 6
                                     is_classname = "FNHELP" + &
                                               String(le_env.PBMajorRevision) + "6"
                            case else
                                     is_classname = "FNHELP" + String(le_env.PBMajorRevision * 10)
                   end choose
         case 17
                   is_classname = "FNHELP" + String(le_env.PBMajorRevision * 10)
         case 19
                   if le_env.PBMinorRevision > 1 then
                            // pb2019 R3 or later:
                            is_classname = "FNHELP"
                   else //pb2019 R2 or earlier:
                            is_classname = "FNHELP" + String(le_env.PBMajorRevision * 10)
                   end if
         case IS > 19
                            is_classname = "FNHELP"                 
end choose
Function long GetClassName ( &
       longptr hWnd, &
       Ref string lpClassName, &
       long nMaxCount &
       ) Library "user32.dll" Alias For "GetClassNameW"
public subroutine wf_setparent ()
String ls_name
LongPtr ll_hWnd
Integer li_rc

//Gets the microhelp handle
ll_hWnd = GetWindow(Handle(gw_frame), 5)
DO UNTIL ll_hWnd = 0
       ls_name = Space(25)
       li_rc = GetClassName(ll_hWnd, ls_name, Len(ls_name))
       If ls_name = is_classname Then
              ll_hWnd = SetParent(Handle(this), ll_hWnd)
              ll_hWnd = 0
       Else
              ll_hWnd = GetWindow(ll_hWnd, 2)
       End If
LOOP