-1

I have a VPS running an app. The app runs if is there a user logged via RDP or not, but for certain functions is required a user is logged via RDP.

Is there a way to my Delphi application detect if is there anyone logged via RDP ? Maybe a Windows API that could do that. What i need is a way to programatically detect if someone is logged on the RDP or not ; the app can run with someone logged or not, but i need to detect when someone is actually logged.

Thanks !

delphirules
  • 6,443
  • 17
  • 59
  • 108
  • How hard did you look? See f.i. https://stackoverflow.com/questions/973802/detecting-remote-desktop-connection – MartynA Feb 07 '19 at 16:56
  • @MartynA I'm looking for a Delphi solution – delphirules Feb 07 '19 at 16:59
  • 1
    And on that page you have this: https://learn.microsoft.com/en-us/windows/desktop/termserv/detecting-the-terminal-services-environment – Jerry Dodge Feb 07 '19 at 17:07
  • 1
    If you look at the article @JerryDodge quoted, which is relatively recent, it shouldn't be hard to code that solution in Delphi; Looks to be not much more than reading a couple of registry keys. – MartynA Feb 07 '19 at 17:24
  • Btw, your q is ambiguous. It's not clear if you are asking: a) How do I detect whether my Delphi app is running under RDP; b) How do I detect that anyone is logged in via RDP to the machine my app is running on; c) other. Which is it? I'm voting to close it until this is clarified. – MartynA Feb 07 '19 at 17:59
  • @MartynA I just edited the question to clarify, thanks. – delphirules Feb 07 '19 at 18:18
  • At the link @MartynA posted (the very first comment here), see the [second answer](https://stackoverflow.com/a/10138591/62576). Although it's not a *Delphi solution*, it's about 10 keystrokes away from being converted to one with minimal knowledge and effort. – Ken White Feb 07 '19 at 18:23
  • Your edit is better (assuming you mean b)), but still not quite clear. When you say "user" do you mean a user of your app, a user of the VPS, an RDP user of the system or a local user of the RDP host? – MartynA Feb 07 '19 at 18:48

1 Answers1

3

The following code lists the user accounts logged in via RDP. It requires the unit JwaWtsApi32.pas from the JEDI API Library & Security Code Library.

uses Windows, SysUtils, Classes,
     JwaWtsApi32;  // https://sourceforge.net/projects/jedi-apilib/

procedure FillRdpUserList (const UserList: TStrings;
                           const bIncludeDomain: Boolean = false;
                           const sServer: String = '');

type
    PWtsSessionInfoArray = ^TWtsSessionInfoArray;
    TWtsSessionInfoArray = array [0..MAXCHAR] of WTS_SESSION_INFO;

var
    iIndex : Integer;
    pWSI : PWtsSessionInfoArray;
    pValue : PChar;
    pCount, dwBytesReturned : DWord;
    hServer : THandle;
    sValue, sDomain : String;
    bConnected : Boolean;
    WtsInfoClass : TWtsInfoClass;
    bUserInfo : Boolean;

begin
    Assert (UserList <> NIL);

    UserList.Clear;

    if (sServer <> '') then
    begin
        hServer := WTSOpenServer (PChar (sServer));

        if (hServer = 0) then
            exit;
    end { if }
    else hServer := WTS_CURRENT_SERVER_HANDLE;

    try
        Win32Check (WtsEnumerateSessions (hServer, 0, 1,
                                          PWTS_SESSION_INFO (pWSI),
                                          pCount));
        for iIndex := 0 to pCount - 1 do
            if (pWSI^[iIndex].State in [WTSActive, WTSDisconnected]) then
            begin
                if (bIncludeDomain) then
                    WtsInfoClass := WTSDomainName
                else WtsInfoClass := WTSUserName;

                bUserInfo := WtsInfoClass = WTSUserName;

                repeat
                    if (WTSQuerySessionInformation (hServer,
                                                    pWSI^[iIndex].SessionId,
                                                    WtsInfoClass,
                                                    Pointer (pValue),
                                                    dwBytesReturned)) then
                    begin
                        sValue := LowerCase (pValue);
                        WtsFreeMemory (pValue);

                        if (sValue <> '') then
                            if (WtsInfoClass = WTSDomainName) then
                                sDomain := sValue + '\'
                            else
                            begin
                                with pWSI^[iIndex] do
                                    if (pWinStationName <> 'Console') then
                                    begin
                                        bConnected := State = WTSActive;
                                        UserList.AddObject (sDomain + sValue,
                                                            TObject (bConnected))
                                    end; { if }

                                sDomain := '';
                            end; { else }

                        if (WtsInfoClass = WTSDomainName) then
                            WtsInfoClass := WTSUserName
                        else bUserInfo := true;
                    end { if }
                    else Break;
                until (bUserInfo);
            end; { if }

    finally
        if (pWSI <> NIL) then
            WtsFreeMemory (pWSI);

        if (sServer <> '') then
            WTSCloseServer (hServer);
    end; { try / finally }
end; { FillRdpUserList }
Olaf Hess
  • 1,453
  • 11
  • 18