Consultor Eletrônico



Kbase P109691: Strange characters returned from a 4GL procedure declared as EXTERNAL (DLL entrypoint).
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   16/10/2008
Status: Unverified

SYMPTOM(s):

Unexpected results returned from a 4GL procedure declared as EXTERNAL (DLL entrypoint).

4GL procedure uses MEMPTR parameters in its signature.

A string is expected to be returned in one of the MEMPTR parameters.

After calling the 4GL procedure, GET-STRING() on one of the MEMPTR variables actually returns strange characters.

CAUSE:

There is a mismatch in signatures between the DLL entrypoint and the Progress 4GL EXTERNAL procedure.

One clear example of such mismatch is demonstrated in case the DLL procedure has the following signature:
DLL written in Microsoft Visual C++:
__declspec( dllexport ) void __stdcall myDLLentrypoint(char **stringOut) {
*stringOut = "The string I intend to return to Progress";
}

DLL written in Delphi:
procedure myDLLentrypoint(var stringOut : PChar); stdcall; export;
begin
stringOut := "The string I intend to return to Progress";
end;

4GL EXTERNAL procedure declaration:
PROCEDURE myDLLentrypoint EXTERNAL "myDLL.dll":
DEFINE OUTPUT PARAMETER pmStringOut AS MEMPTR.
END.

In this case, what the DLL procedure expects is the address for the variable containing the address for the string [double indirection]. This is something that Progress does not support: whether you specify the INPUT or OUTPUT qualifier for the MEMPTR parameter in the EXTERNAL procedure, and whether you specify the HANDLE TO option or not, what Progress will pass to the DLL procedure is the address of the MEMPTR variable [single indirection]; the "strange characters" that you see by using GET-STRING() on the MEMPTR parameter, is actually the address of the real string, rather than the string itself.

FIX:

Make sure that the signature between the DLL entrypoint and the Progress 4GL EXTERNAL procedure.

Keep in mind that the 4GL cannot handle double indirection, which means that if you do not have control over the DLL, then unfortunately you cannot interface to it from the 4GL.
On the other hand, if you do have control over the DLL source code, then what follows is a possible change to the sample source code above:

Microsoft Visual C++:
__declspec( dllexport ) void __stdcall myDLLentrypoint(char *stringOut) {
strcpy(stringOut, "The string I intend to return to Progress");
}

DLL written in Delphi:
procedure myDLLentrypoint(stringOut : PChar); stdcall; export;
begin
StrCopy(stringOut, "The string I intend to return to Progress");
end;

4GL EXTERNAL procedure declaration:
PROCEDURE myDLLentrypoint EXTERNAL "myDLL.dll":
DEFINE INPUT PARAMETER pmStringOut AS MEMPTR.
END.

(please note the usage of strcpy() in C++ and StrCopy() in Delphi; simple assignment of the string to stringOut will not work!)

Sample usage of myDLLentrypoint from the 4GL:

SET-SIZE(myMemptr) = 64. /* Enough to store the string, plus
the null terminator. */
RUN myDLLentrypoint (myMemptr).
MESSAGE GET-STRING(myMemptr, 1) VIEW-AS ALERT-BOX.
SET-SIZE(myMemptr) = 0. /* Release the memory */