WTSQuerySessionInformation returning empty strings

Benj picture Benj · May 13, 2010 · Viewed 11.5k times · Source

I've written a program which should query the Terminal Services API and print out some state information about the sessions running on a terminal services box. I'm using the WTSQuerySessionInformation function to do this and it's returning some data but most of the data seems to be missing... Does anyone know why?

Here's my program:

void WTSGetString( HANDLE serverHandle, DWORD sessionid, WTS_INFO_CLASS command, wchar_t* commandStr) 
{
    DWORD bytesReturned = 0;
    LPTSTR pData = NULL;
    if (WTSQuerySessionInformation(serverHandle, sessionid, command, &pData, &bytesReturned))
    {
        wprintf(L"\tWTSQuerySessionInformationW - session %d - %s returned \"%s\"\n", sessionid, commandStr, pData);    
    }
    else
    {
        wprintf(L"\tWTSQuerySessionInformationW - session %d - %s failed - error=%d - ", sessionid, commandStr, GetLastError());
        printLastError(NULL, GetLastError());
    }
    WTSFreeMemory(pData);
}


void ExtractFromWTS( HANDLE serverHandle, DWORD sessionid ) 
{

    WTSGetString(serverHandle, sessionid, WTSInitialProgram, L"WTSInitialProgram");
    WTSGetString(serverHandle, sessionid, WTSApplicationName, L"WTSApplicationName");
    WTSGetString(serverHandle, sessionid, WTSWorkingDirectory, L"WTSWorkingDirectory");
    WTSGetString(serverHandle, sessionid, WTSOEMId, L"WTSOEMId");
    WTSGetString(serverHandle, sessionid, WTSSessionId, L"WTSSessionId");
    WTSGetString(serverHandle, sessionid, WTSUserName, L"WTSUserName");
    WTSGetString(serverHandle, sessionid, WTSWinStationName, L"WTSWinStationName");
    WTSGetString(serverHandle, sessionid, WTSDomainName, L"WTSDomainName");
    WTSGetString(serverHandle, sessionid, WTSConnectState, L"WTSConnectState");
    WTSGetString(serverHandle, sessionid, WTSClientBuildNumber, L"WTSClientBuildNumber");
    WTSGetString(serverHandle, sessionid, WTSClientName, L"WTSClientName");
    WTSGetString(serverHandle, sessionid, WTSClientDirectory, L"WTSClientDirectory");
    WTSGetString(serverHandle, sessionid, WTSClientProductId, L"WTSClientProductId");
    WTSGetString(serverHandle, sessionid, WTSClientHardwareId, L"WTSClientHardwareId");
    WTSGetString(serverHandle, sessionid, WTSClientAddress, L"WTSClientAddress");
    WTSGetString(serverHandle, sessionid, WTSClientDisplay, L"WTSClientDisplay");
    WTSGetString(serverHandle, sessionid, WTSClientProtocolType, L"WTSClientProtocolType");
}

int _tmain(int argc, _TCHAR* argv[])
{
    PWTS_SESSION_INFOW ppSessionInfo = 0;
    DWORD pCount;
    if(!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppSessionInfo, &pCount))
    {
        printLastError(L"WTSEnumerateSessions", GetLastError());
        return 1;
    }

    wprintf(L"%d WTS sessions found on host\n", pCount);

    for (unsigned int i=0; i<pCount; i++)
    {
        wprintf(L"> session=%d, stationName = %s\n", ppSessionInfo[i].SessionId, ppSessionInfo[i].pWinStationName);
        ExtractFromWTS(WTS_CURRENT_SERVER_HANDLE, ppSessionInfo[i].SessionId);
        LPWSTR sessionstr = new wchar_t[200];
        wsprintf(sessionstr, L"%d", ppSessionInfo[i].SessionId);    
    }

    return 0;
}

And here's the output:

C:\Users\Administrator\Desktop>ObtainWTSStartShell.exe empserver1
4 WTS sessions found on host
> session=0, stationName = Services
        WTSQuerySessionInformationW - session 0 - WTSInitialProgram failed - error=87 - The paramete
r is incorrect.

        WTSQuerySessionInformationW - session 0 - WTSApplicationName failed - error=87 - The paramet
er is incorrect.

        WTSQuerySessionInformationW - session 0 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 0 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 0 - WTSSessionId returned ""
        WTSQuerySessionInformationW - session 0 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 0 - WTSWinStationName returned "Services"
        WTSQuerySessionInformationW - session 0 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 0 - WTSConnectState returned "♦"
        WTSQuerySessionInformationW - session 0 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientDisplay returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=1, stationName = Console
        WTSQuerySessionInformationW - session 1 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 1 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 1 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 1 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 1 - WTSSessionId returned "☺"
        WTSQuerySessionInformationW - session 1 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 1 - WTSWinStationName returned "Console"
        WTSQuerySessionInformationW - session 1 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 1 - WTSConnectState returned "☺"
        WTSQuerySessionInformationW - session 1 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientDisplay returned "?"
        WTSQuerySessionInformationW - session 1 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=3, stationName = RDP-Tcp#0
        WTSQuerySessionInformationW - session 3 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 3 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 3 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 3 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 3 - WTSSessionId returned "♥"
        WTSQuerySessionInformationW - session 3 - WTSUserName returned "Administrator"
        WTSQuerySessionInformationW - session 3 - WTSWinStationName returned "RDP-Tcp#0"
        WTSQuerySessionInformationW - session 3 - WTSDomainName returned "EMPSERVER1"
        WTSQuerySessionInformationW - session 3 - WTSConnectState returned ""
        WTSQuerySessionInformationW - session 3 - WTSClientBuildNumber returned "?"
        WTSQuerySessionInformationW - session 3 - WTSClientName returned "APWADEV03"
        WTSQuerySessionInformationW - session 3 - WTSClientDirectory returned "C:\Windows\System32\m
stscax.dll"
        WTSQuerySessionInformationW - session 3 - WTSClientProductId returned "☺"
        WTSQuerySessionInformationW - session 3 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 3 - WTSClientAddress returned "☻"
        WTSQuerySessionInformationW - session 3 - WTSClientDisplay returned "?"
        WTSQuerySessionInformationW - session 3 - WTSClientProtocolType returned "☻"
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=65536, stationName = RDP-Tcp
        WTSQuerySessionInformationW - session 65536 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 65536 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 65536 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSSessionId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSWinStationName returned "RDP-Tcp"
        WTSQuerySessionInformationW - session 65536 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSConnectState returned "♠"
        WTSQuerySessionInformationW - session 65536 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientDisplay returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe

As you can see, some of the data looks valid, but not all....

Answer

jon picture jon · Apr 19, 2011

Even though WTSQuerySessionInformation takes a LPTSTR to hold the data returned, the data isn't always a string. Trying to printf something that isn't a string won't work very well in most cases. The fact that you're seeing empty/garbage strings means that sometimes the buffer pointed to by the LPTSTR starts with a '\0' if read as a string, which printf will print as the empty string.

Instead try printing out each character of the string in HEX representation. Iterate through each character in the string (0 through bytesReturned-1) and print it as hex. That will give you a better idea of what's in the LPTSTR buffer.