Consultor Eletrônico



Kbase 16581: Porting 4GL Code Which Calls DLL's from 16-Bit to 32-Bit
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   15/10/2008
Status: Verified

GOAL:

Using 4GL code originally accessing 16-Bit DLLs with 32-Bit Progress.

GOAL:

How to use 4GL code originally accessing 16-Bit DLLs with 32-Bit Progress.

FACT(s) (Environment):

Windows DLL

FIX:

Any 4GL code which defines and accesses a 16-Bit DLL entry point will
have to be looked at when using the 32-Bit version of Progress. This
includes 3rd party DLLs as well as calls made in to the Windows API.


There is a high probability that this code will have to be modified. You should contact the vendor of the DLL for information on the changes between the 16-bit and the 32-bit versions of the DLLs.

ISSUES:

-  16-Bit DLLs cannot be used by 32-Bit Progress.

You must supply a 32-Bit version of the 16-Bit DLL.  It is possible that the name is not the same.  You can elect to rename the DLL or change your procedure definitions.  When running Windows NT, it is likely that the entry points for Windows API calls have an "A" appended to the entry point name.  This is to distinguish between the ASCII version of the API and the UNICODE version of the API.

-  The entry points for 32-Bit DLLs may be case-sensitive.

You should check with the manufacturer of the DLLs you are using. All of the Windows API calls are now case sensitive.

-  Integer parameters change from SHORT to LONG.

Since an integer is a 32-Bit value on Win32, it must be defined as a LONG in your procedure definitions.  You should verify this information with the manufacturer of the DLLs you are using as in some cases a SHORT may still be required.

-  Some of the entry points and their parameters have changed in the Win32 API.

You should look at every entry point and make sure that your procedure definition is still correct.

For example, a call to GetWindowRect in Windows 3.1 would look like the following:

PROCEDURE GetWindowRect EXTERNAL "USER.EXE":
       DEFINE INPUT  PARAMETER hWnd   AS SHORT.
       DEFINE OUTPUT PARAMETER lpRect AS MEMPTR.
  END PROCEDURE.

In the Win32 API, the GetWindowRect function has the following differences:

1)  The function resides in a different file (USER32.DLL).
2)  hWnd is now 32 bits and turns from a SHORT to a LONG.
3)  lpRect is now defined as a structure of LONGs instead of a structure of SHORTs.

   PROCEDURE GetWindowRect EXTERNAL "USER32.DLL":
       DEFINE INPUT  PARAMETER hWnd   AS LONG.
       DEFINE OUTPUT PARAMETER lpRect AS MEMPTR.
   END PROCEDURE.

-  How to port your 4GL code such that it works on 16-Bit and 32-Bit versions of Progress.

You should rely on the value returned by the OPSYS function to determine which 4GL code to execute.  OPSYS returns 'WIN32' when running the 32-Bit version of Progress for Windows and returns 'MSDOS' when running the 16-Bit version of Progress for Windows. The Progress 4GL cannot compile a 4GL procedure which contains more than one internal procedure of the same name.  So, how do you
support two GetWindowRect calls in your code (one each for 16-Bit and 32-Bit)?  Since an entry point can be called via its ordinal number, you can rename one or both of the procedure definitions to make them unique.  You can get the ordinal of an entry point in a DLL by right-clicking on the DLL and selecting "Quick View" from the popup menu.

Here's an example showing how to rewrite a DLL call between 16-bit and 32-bit Progress.  This example assumes that the 16-bit DLL shows "32" as the ordinal number for the function:

   PROCEDURE GetWindowRect EXTERNAL "USER32.DLL":
       DEFINE INPUT  PARAMETER hWnd   AS LONG.
       DEFINE OUTPUT PARAMETER lpRect AS MEMPTR.
   END PROCEDURE.

  PROCEDURE GetWindowRect16 EXTERNAL "USER.EXE" ORDINAL 32:
      DEFINE INPUT  PARAMETER hWnd   AS SHORT.
       DEFINE OUTPUT PARAMETER lpRect AS MEMPTR.
   END PROCEDURE.

Notice that I have renamed the entry point of the 16-Bit version to 'GetWindowRect16' and specified the ordinal number of 32. In this case, Progress will use the ordinal number to find the entry point instead of using the name.

Using an excerpt from PR.OTOOLS/_SCRCAP.W, I'll show how to call the correct entry point at runtime.

   IF OPSYS = 'WIN32' THEN
    DO:    /* call 32-bit version */
           RUN GetWindowRect(MSwindow_hdl, OUTPUT wrect).
           SET-SIZE(wrect) = 16. /* 4 INTEGERS AT 4 BYTES EACH */
           ASSIGN wrect-left   = GET-LONG(wrect,1)
                  wrect-top    = GET-LONG(wrect,5)
                  wrect-right  = GET-LONG(wrect,9)
                  wrect-bottom = GET-LONG(wrect,13).
       END.
  ELSE
      DO:    /* call 16-bit version */
          RUN GetWindowRect16(MSwindow_hdl, OUTPUT wrect).
           SET-SIZE(wrect) = 8. /* 4 INTEGERS AT 2 BYTES EACH */
           ASSIGN wrect-left   = GET-LONG(wrect,1)
                  wrect-top    = GET-LONG(wrect,3)
                  wrect-right  = GET-LONG(wrect,5)
                  wrect-bottom = GET-LONG(wrect,7).
       END.
.