Reading the name of the client using Wtsapi32.dll does not w

Posted by Toni Perätalo on 26-Feb-2018 08:32

Hi,

We are using wtsapi32.dll to get name of the client. Needed when running the application on Remote Desktop Server. This has worked for years, but now when we upgraded to OE 11.7.2 (hotfix 4), OE crashes when using that. 

Here is the code, to clarify this:

PROCEDURE WTSQuerySessionInformationA EXTERNAL "wtsapi32.dll":
    DEFINE INPUT PARAMETER hServer AS LONG.
    DEFINE INPUT PARAMETER SessionId AS LONG.
    DEFINE INPUT PARAMETER WTSInfoClass AS LONG.
    DEFINE OUTPUT PARAMETER ppBuffer AS LONG.
    DEFINE OUTPUT PARAMETER pBytesReturned AS LONG.
    DEFINE RETURN PARAMETER intResult AS LONG. 
END PROCEDURE.

FUNCTION FuncClientName RETURNS CHARACTER(  ) :

    DEFINE VARIABLE lpInfoClass AS INT64 NO-UNDO.
    DEFINE VARIABLE lpName AS MEMPTR NO-UNDO.
    DEFINE VARIABLE ws-client-name AS CHARACTER NO-UNDO.
    DEFINE VARIABLE BytesReturned AS INT64 NO-UNDO.
    DEFINE VARIABLE intResult AS INT64 NO-UNDO.
    
    RUN WTSQuerySessionInformation(INPUT 0, /* {&WTS_CURRNET_SERVER_HANDLE} */
                                   INPUT -1, /* {&WTS_CURRENT_SESSION} */
                                   INPUT 10, /* {&WTS_CLASS_INFO} 10 = WTSClientName */
                                   OUTPUT lpInfoClass,
                                   OUTPUT BytesReturned,
                                   OUTPUT intResult).
   
    SET-POINTER-VALUE(lpName) = lpInfoClass. // this crashes the OE
    ASSIGN ws-client-name = GET-STRING(lpName,1). 
    SET-SIZE(lpName) = 0.
    RETURN (ws-client-name). /* Function return value. */
END FUNCTION.

So, WTSQuerySessionInformation returns lpInfoClass value that is used to get the information needed. When executing the SET-POINTER-VALUE, OE crashes "OpenEdge Graphical client has stopped working" and generates protrace.

I noticed that when running this on OE 11.7, it sometimes returns negative values. But that's not the case. Even if lpInfoClass is positive, the system crashes. So the value is not valid somehow. And the problem is only when running on OE 11.7. Using OE 11.6.3 with same source code, same db, same platform, everything works fine.

How can this external dll call return a wrong memory pointer(?) on OE 11.7 but on OE 11.6 it is returned correctly? Has anyone else noticed this kind of behavior? Are there any better resolutions to get the client name on Remote desktop server? And no, the IP address stored in _Connect is not enough. Could this be a bug in OE?

Tested platforms: Windows 10 64 bit (Local databases, local OE, not RDC but still crashes on OE 11.7. works with OE 11.6), Windows Server 2012 R2 Standard (RDS) 64 bit. OE 11.7.2 hotfix 004. 

Any ideas are highly appreciated. 

Regards,

Toni

Posted by Matt Gilarde on 26-Feb-2018 08:47

The ppBuffer and pBytesReturned parameters in the declaration of external procedure WTSQuerySessionInformationA must be INT64 if you're running on 64-bit OpenEdge. These parameters are pointer values and pointers are 64-bits wide in  64-bit processes. The crash is occurring because the value returned in the ppBuffer parameter is being truncated to 32 bits.

I won't go into the technical details but this problem could potentially have happened with 11.6. It's almost guaranteed to happen with 11.7 due to changes in recent versions of Windows and a change in the compiler we use to build OpenEdge in 11.7.

All Replies

Posted by Matt Gilarde on 26-Feb-2018 08:47

The ppBuffer and pBytesReturned parameters in the declaration of external procedure WTSQuerySessionInformationA must be INT64 if you're running on 64-bit OpenEdge. These parameters are pointer values and pointers are 64-bits wide in  64-bit processes. The crash is occurring because the value returned in the ppBuffer parameter is being truncated to 32 bits.

I won't go into the technical details but this problem could potentially have happened with 11.6. It's almost guaranteed to happen with 11.7 due to changes in recent versions of Windows and a change in the compiler we use to build OpenEdge in 11.7.

Posted by Roger Blanchard on 26-Feb-2018 09:02

Are you running this code on the RDP server to get the client or are you running that code on the client? We just use System.Environment:GetEnvironmentVariable to get the client name.

cClientName = System.Environment:GetEnvironmentVariable("CLIENTNAME").

cSessionName = System.Environment:GetEnvironmentVariable("SESSIONNAME").

Posted by Stefan Drissen on 26-Feb-2018 09:24
Posted by Toni Perätalo on 27-Feb-2018 07:56

Awesome! Thank you [mention:931f7f12516e4daa930b60341926d260:e9ed411860ed4f2ba0265705b8793d05] ! That solved the problem.

Posted by Toni Perätalo on 27-Feb-2018 08:05

[mention:011caad85a5545659f1a1aaf22be3887:e9ed411860ed4f2ba0265705b8793d05] We are using that code to find out whether the application is run on RDP server or on the client. When run on RDP server, it returns the client name. Otherwise it returns empty. So we know where it is run.

It seems that System.Environment:GetEnvironmentVariable("CLIENTNAME"). works similarly (well returns ? when run on client, but...). I wasn't aware of that kind of class/method, so that's good to know. Probably we start using that one later.

Thank you!

Posted by Mike Fechner on 27-Feb-2018 08:11

Maybe old-fashioned, but this works as well:

MESSAGE OS-GETENV ("CLIENTNAME")
    VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.

Posted by bronco on 27-Feb-2018 08:19

Indeed Mike! I'm wondering why "everybody" want to use .NET all the time when there are 4GL (and portable) constructs available...

Posted by Roger Blanchard on 27-Feb-2018 08:38

We use .NET in cases where there is not a 4GL equivalent or if the 4GL equivalent has issues. One that stands out is the FILE-INFO....1000 faster use .NET.

Posted by j.kattestaart on 27-Feb-2018 08:48

There were days i preferred the 4GL syntax too, but somehow i like the .NET more, however it would be nice if the .NET bridge would also support the new .NET Standard calls.

@Mike i would hardly consider OS-GETENV ("CLIENTNAME") a native 4GL solutions because its just using the Command evenironment variables from windows or should i say DOS....;-)

Posted by jquerijero on 05-Mar-2018 10:06

One thing to watch out when using CLIENTNAME, it will not refresh the environment variable when taking over an existing session. This means if you continue an existing session on another client PC, CLIENTNAME will still say you are on the old PC. This could happen if you accidentally closed the RDP window then login on another machine.

This thread is closed