Feedback
Did this article resolve your question/issue?

   

Article

Windows API call fails with error 13712 in 11.7 64-bit and later

« Go Back

Information

 
TitleWindows API call fails with error 13712 in 11.7 64-bit and later
URL NameWindows-API-call-fails-with-error-13712-in-11-7-64-bit
Article Number000188861
EnvironmentProduct: OpenEdge
Version: 11.7.x 64-bit, 12.x 64-bit
OS: Windows
Question/Problem Description
Windows API call fails with error 13712 in OpenEdge 11.7.x 64-bit.

Windows API call fails with error 13712 in OpenEdge 12.x 64-bit.

Calls to GetMonitorInfoA and SendMessageA (and possibly others) fail with error 13712 in 11.7 and 12.x 64-bit.

Problem does not occur when running the same code in 11.7.x 32-bit.

Problem does not occur when running the same code in 11.6.x 64-bit.

Problem does not occur when running the same code in 11.7.x 64-bit on Windows 7.
Steps to ReproduceCode to reproduce:

DEFINE VARIABLE imonitor         AS INTEGER     NO-UNDO.
DEFINE VARIABLE mptrMonitorInfo  AS MEMPTR      NO-UNDO.
DEFINE VARIABLE ireturnvalue     AS INTEGER     NO-UNDO.

SET-SIZE( mptrMonitorInfo ) = 40. /* 4 + 16 + 16 + 4 */.
PUT-LONG( mptrMonitorInfo, 1 ) = GET-SIZE( mptrMonitorInfo ).

RUN GetMonitorInfoA ( 
   iMonitor, 
   GET-POINTER-VALUE( mptrMonitorInfo ), 
   OUTPUT iReturnValue 
).

PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
   DEFINE INPUT         PARAMETER hMonitor      AS LONG  NO-UNDO.
   DEFINE INPUT         PARAMETER lpMonitorInfo AS LONG NO-UNDO.
   DEFINE       RETURN  PARAMETER ReturnValue   AS LONG  NO-UNDO.
END PROCEDURE. /* GetMonitorInfoA */
Clarifying Information
Per the Online documentation for the GET-POINTER-VALUE function:
"Returns, as an INT64 value, the address of (or pointer to) the memory region associated with the specified MEMPTR variable. The returned value is based on whether the platform supports 64-bit pointers or 32-bit pointers. On a 32-bit platform, the value never gets bigger than 2GB."

A LONG is a 32-bit value and (for example) 2932350975264 is too large to fit in 32 bits. 
Error MessageValue does not fit in DLL datatype. (13712)

Value 2932350975264 does not fit in long DLL datatype. (13712)

'C' Call Stack has been compromised after calling in (6069)

'C' Call Stack has been compromised after calling GetMonitorInfoA in user32 (6069)
Defect/Enhancement Number
Cause
This is expected behavior. GET-POINTER-VALUE on a MEMPTR is returning a 64-bit pointer. Nothing has been changed with the way that GET-POINTER-VALUE specifically works; it always had the capacity to return 64-bit pointers. The same issue could potentially have been encountered in 11.6.3 and lower but it is much more likely to happen in 11.7 on Windows 8.1 and Windows 10 because of a) a change to how OpenEdge executables are compiled and b) a change in newer versions of Windows.
Resolution
Change parameter from LONG to INT64. Using INT64 is correct. lpMonitorInfo is a pointer and pointer values in 64-bit processes are 64-bit values. Technically, hMonitor should also be an INT64 in 64-bit processes but Windows allows you to use 32-bit values for handles. For example,
RUN GetMonitorInfoA ( 
   iMonitor, 
   GET-POINTER-VALUE( mptrMonitorInfo ), 
   OUTPUT iReturnValue 
).

PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
   DEFINE INPUT         PARAMETER hMonitor      AS LONG  NO-UNDO.
   DEFINE INPUT         PARAMETER lpMonitorInfo AS INT64 NO-UNDO.
   DEFINE       RETURN  PARAMETER ReturnValue   AS LONG  NO-UNDO.
END PROCEDURE. /* GetMonitorInfoA */
Workaround
For applications that run on both 32-bit and 64-bit clients, the &PROCESS-ARCHITECTURE preprocessor or PROCESS-ARCHITECTURE function can be used to control the declaration types.

Option #1 - &PROCESS-ARCHITECTURE preprocessor
Requires that the compiler architecture matches runtime architecture, e.g. 64.bit definitions will be used in r-code when compiled with a 64-bit client.
&IF {&PROCESS-ARCHITECTURE} = 64 &THEN
     PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
          DEFINE INPUT PARAMETER hMonitor AS INT64 NO-UNDO.
          DEFINE INPUT PARAMETER lpMonitorInfo AS INT64 NO-UNDO.
          DEFINE RETURN PARAMETER ReturnValue AS INT64 NO-UNDO.
     END PROCEDURE. /* GetMonitorInfoA */
&ELSE
     PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
          DEFINE INPUT PARAMETER hMonitor AS LONG NO-UNDO.
          DEFINE INPUT PARAMETER lpMonitorInfo AS LONG NO-UNDO.
          DEFINE RETURN PARAMETER ReturnValue AS LONG NO-UNDO.
     END PROCEDURE. /* GetMonitorInfoA */
&ENDIF


Option #2 - PROCESS-ARCHITECTURE function
Requires the WinAPI call to be moved to an external procedure to avoid duplicate procedures, plus some minor code tweaks. 
/* runner.p */

DEFINE VARIABLE imonitor        AS INTEGER NO-UNDO.
DEFINE VARIABLE mptrMonitorInfo AS MEMPTR  NO-UNDO.
DEFINE VARIABLE ireturnvalue    AS INTEGER NO-UNDO.

SET-SIZE( mptrMonitorInfo ) = 40. /* 4 + 16 + 16 + 4 */.
PUT-LONG( mptrMonitorInfo, 1 ) = GET-SIZE( mptrMonitorInfo ).

IF PROCESS-ARCHITECTURE = 64 THEN
    RUN GetMonitorInfoA64.p (iMonitor, mptrMonitorInfo, OUTPUT iReturnValue).
ELSE
    RUN GetMonitorInfoA32.p (iMonitor, mptrMonitorInfo, OUTPUT iReturnValue).

MESSAGE iReturnValue
    VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
/* GetMonitorInfoA64.p */

DEFINE INPUT PARAMETER imonitor         AS INTEGER     NO-UNDO.
DEFINE INPUT PARAMETER mptrMonitorInfo  AS MEMPTR      NO-UNDO.
DEFINE OUTPUT PARAMETER ireturnvalue     AS INTEGER     NO-UNDO.

RUN GetMonitorInfoA ( 
    iMonitor, 
    GET-POINTER-VALUE( mptrMonitorInfo ), 
    OUTPUT iReturnValue 
    ).

SET-SIZE(mptrMonitorInfo) = 0.

PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
    DEFINE INPUT PARAMETER hMonitor AS INT64 NO-UNDO.
    DEFINE INPUT PARAMETER lpMonitorInfo AS INT64 NO-UNDO.
    DEFINE RETURN PARAMETER ReturnValue AS INT64 NO-UNDO.
END PROCEDURE. /* GetMonitorInfoA */
/* GetMonitorInfoA32.p */

DEFINE INPUT PARAMETER imonitor         AS INTEGER     NO-UNDO.
DEFINE INPUT PARAMETER mptrMonitorInfo  AS MEMPTR      NO-UNDO.
DEFINE OUTPUT PARAMETER ireturnvalue     AS INTEGER     NO-UNDO.

RUN GetMonitorInfoA ( 
    iMonitor, 
    GET-POINTER-VALUE( mptrMonitorInfo ), 
    OUTPUT iReturnValue 
    ).

SET-SIZE(mptrMonitorInfo) = 0.

PROCEDURE GetMonitorInfoA EXTERNAL "user32":u:
    DEFINE INPUT PARAMETER hMonitor AS LONG NO-UNDO.
    DEFINE INPUT PARAMETER lpMonitorInfo AS LONG NO-UNDO.
    DEFINE RETURN PARAMETER ReturnValue AS LONG NO-UNDO.
END PROCEDURE. /* GetMonitorInfoA */
Notes
Note setting the parameters to INT64 and running on 32-bit OpenEdge can result in error 6069 so ensuring that the correct definitions are used is required.


References to other documentation:

Progress article(s):
"Moving to 64 bits: DLLs and OCXs"
Last Modified Date11/20/2020 6:53 AM
Attachment 
Files
Disclaimer The origins of the information on this site may be internal or external to Progress Software Corporation (“Progress”). Progress Software Corporation makes all reasonable efforts to verify this information. However, the information provided is for your information only. Progress Software Corporation makes no explicit or implied claims to the validity of this information.

Any sample code provided on this site is not supported under any Progress support program or service. The sample code is provided on an "AS IS" basis. Progress makes no warranties, express or implied, and disclaims all implied warranties including, without limitation, the implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample code is borne by the user. In no event shall Progress, its employees, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample code, even if Progress has been advised of the possibility of such damages.