Idle time in a T.S. session - how to get it?

424 views
Skip to first unread message

Chuck Chopp

unread,
May 5, 2004, 12:23:04 PM5/5/04
to
The documented information classes for WTSQuerySessionInformation() do not
allow for the idle time for a session to be retrieved. However, the
Terminal Services Manager is capable of retrieving & displaying this
information for each session.

Is there an undocumented information class that can be used to obtain this
information, or else perhaps a different API function [possibly undocumented]?

I did some Google searches on "WTSQuerySessionInformation" and "idle" and
did not come up with anything other than a few other previous posts asking
the same question.


TIA,

Chuck
--
Chuck Chopp

ChuckChopp (at) rtfmcsi (dot) com http://www.rtfmcsi.com

RTFM Consulting Services Inc. 864 801 2795 voice & voicemail
103 Autumn Hill Road 864 801 2774 fax
Greer, SC 29651

Do not send me unsolicited commercial email.

Rhett Gong [MSFT]

unread,
May 7, 2004, 1:12:38 AM5/7/04
to
Hi Chuck,
From your description, you would like to get the idle time of a TS session.

So far as I know, there is no api for it.
Since Query command could output this informatio, I think we could parse
the output of "query user" for it. (reference KB186592 for more information
on Terminal Server Commands: QUERY) Currently, I am still trying to find a
better way for this problem. I will post a reply in this thread if I have
any update. :)

Have a nice day!

Rhett Gong [MSFT]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.
Please reply to newsgroups only. Thanks.

Chuck Chopp

unread,
May 7, 2004, 7:17:45 AM5/7/04
to
Rhett Gong [MSFT] wrote:
> Hi Chuck,
> From your description, you would like to get the idle time of a TS session.
>
> So far as I know, there is no api for it.
> Since Query command could output this informatio, I think we could parse
> the output of "query user" for it. (reference KB186592 for more information
> on Terminal Server Commands: QUERY) Currently, I am still trying to find a
> better way for this problem. I will post a reply in this thread if I have
> any update. :)

Rhett,

Unfortunately, the QUERY command doesn't actually show the idle time.
"QUERY SESSION" does not even show a column for this data item, while "QUERY
USER" shows a column but never populates a value [always says "none"] when
it shows records of output.

The only utility that seems to be able to obtain & display the session idle
time information is the MMC snap-in "Terminal Services Manager". I need to
figure out how that particular utility is obtaining this information.


Regards,

John Eikanger [MSFT]

unread,
May 12, 2004, 2:25:21 PM5/12/04
to
Hi, Chuck

Rhett has escalated this issue to me and I have consulted with the people
who ought to know the answer.

There is no way to do this in the current product. There is no public API
and there is no supported way to get the information.

If you could share what you are trying to do with the idle time once you
have it, we may be able to suggest another way to get there.

Hope this helps,

John Eikanger
Microsoft Developer Support

This posting is provided “AS IS” with no warranties, and confers no rights.

--------------------
| Date: Fri, 07 May 2004 07:17:45 -0400
| From: Chuck Chopp <Chuck...@rtfmcsi.com>
| Organization: RTFM Consulting Services Inc.
| Subject: Re: Idle time in a T.S. session - how to get it?
| X-Tomcat-NG: microsoft.public.win32.programmer.kernel

Chuck Chopp

unread,
May 12, 2004, 3:53:57 PM5/12/04
to
John Eikanger [MSFT] wrote:

> Rhett has escalated this issue to me and I have consulted with the people
> who ought to know the answer.
>
> There is no way to do this in the current product. There is no public API
> and there is no supported way to get the information.
>
> If you could share what you are trying to do with the idle time once you
> have it, we may be able to suggest another way to get there.

John,

I was afraid you might say that. I was hoping that there was an
undocumented WTSInfoClass value to pass in to WTSQuerySessionInformation()
that would obtain the information. Perhaps there is a WMI provider for
temrinal services that supplies this information. Since the QUERY SESSION
and QUERY USER commands have fields reserved for this value [but no actual
values in the fields] in their display output, and since the Terminal
Services Manager actually shows the idle time for each session, there has to
be some way for the information to be obtained. Maybe the API function
isn't officially documented, but surely it or a WMI interface must exist for
that admin utility to obtain the information. I suspect that even if there
isn't a regular Win32 API function to get this information, there's a kernel
API function that can get it which can be called from user mode code such as
the Zw*() functions upon which many Win32 API functions are based.

I was mistaken before in thinking that Terminal Services Manager was a MMC
snap-in. It is actually a separate program named TSADMIN.EXE. A quick
review of it with the Dependency Walker and I can see that it does not
depend on WTSAPI32.DLL at all. Instead, it is linked against WINSTA.DLL,
which is providing all of the necessary access to the underlying terminal
server session information. A review of WTSAPI32.DLL in Dependency Viewer
shows that it, too, is linked to WINSTA.DLL. At this point, I would be
interested in finding out more information about WINSTA.DLL and the usage of
the functions that it exports.

Of interest to me are the following functions in WINSTA.DLL:

WinStationEnumerateA()
WinStationQueryInformationA()

I suspect that it is the 2nd of those 2 functions that will provide the
information that I'm looking for, but I wouldn't know for certain until I
see something in the way of supporting documentation.

As for the purpose that is information is being gathered, I have some code
that wraps up the WTS*() API functions and makes them readily usable from
within a scripting language. One of the end-users of that scripting
language asked why all of the other session information could be obtained
but the idle time couldn't be obtained. I've been researching it ever since.

John Eikanger [MSFT]

unread,
May 12, 2004, 5:40:34 PM5/12/04
to
Hi, Chuck

What I was looking for was information on how you were planning to use the
idle time once you obtained it. I was hoping that there might be a way of
getting you there that did not require the idle time. It does not look
like that is an option.

The information you have requested on the 2 functions exposed by the file
winsta.dll is not published and the functions are undocumented. The use of
these functions is unsupported.

I'm sorry, but that's all I can give you.

John Eikanger
Microsoft Developer Support

This posting is provided “AS IS” with no warranties, and confers no rights.
--------------------

| Date: Wed, 12 May 2004 15:53:57 -0400
| From: Chuck Chopp <Chuck...@rtfmcsi.com>


|| Subject: Re: Idle time in a T.S. session - how to get it?
|| X-Tomcat-NG: microsoft.public.win32.programmer.kernel
|

Philip_C

unread,
May 17, 2004, 5:16:02 AM5/17/04
to
Hello, i've got the same problem, i've searched for about 3 months to find a way to retrieve idle time and connection date/time for a Terminal Server session, but it seems that there is no 'public' function to do that.

However, i would like to mention a piece of software which is capable of doin it : Dameware NT Utilities. This piece of software is providing all the informations we are wishing to display.
I would like to know if Microsoft gave them the necessary functions or API to do it or if they are partners. Cause if partnership is necessary to get the API needed, i will be happy to try to make it happen.

Anyway, i know that it's not possible to use WMI to get Idle time or Session Logon Time regarding a Win 2000 server. WMI is really usefull but the TS session informations are available only requesting a W2k3 Server.

Chuck Chopp

unread,
May 17, 2004, 10:04:05 AM5/17/04
to
Philip_C wrote:

I'm now fairly certain that the desired information is obtained either by
using an undocumented WTSInfoClass value when calling
WTSQuerySessionInformation(), or it is obatined by using an undocumented
function in WINSTA.DLL, most likely WinStationQueryInformationA().

When I get some time later this week, I'll be experimenting with those
functions to see if I can get the information. If Dameware NT Utilities is
returning this information, then the developers of that product went through
the exact same exercise to figure out how to get the information. I just
need to spend some quality time with the debugger to figure it out. When I
do figure it out, I'll post about it here.

Philip_C

unread,
May 17, 2004, 10:51:04 AM5/17/04
to
Great thank you, i'll keep an eye on it.
By the way i'm still searching a way to retrieve those idle time and the date/time of each connected TS session, i'll post here if i finally find something too.

Chuck Chopp

unread,
May 21, 2004, 5:01:46 PM5/21/04
to
Philip_C wrote:

> Great thank you, i'll keep an eye on it.
> By the way i'm still searching a way to retrieve those idle time and the date/time of each connected TS session, i'll post here if i finally find something too.

Victory is mine. It took a few days and many hours of quality time spent
with WinDbg, but I figured out how to get the session times. Reviewing the
Citrix Server SDK docs helped as it clued me in to what format the session
time values would be encoded in. As it turns out, they are 64-bit integer
values like you'd find in the FILETIME structure. I started up TSADMIN.EXE
and then attached to it with WinDbg. Then, I set some breakpoints in
WINSTA.DLL to trap all calls to WinStationQueryInformationW() as that was
where I expected TSADMIN to be calling to get this information. After a lot
of single stepping, dumping memory, dumping the stack and reviewing register
values, I was able to determine what information class value is needed, how
large the return buffer has to be and how the buffer contents needs to be
interpreted.

Combining the results of my analysis along with the very limited information
that is provided in WINTERNL.H, I've come up with the following 'C' language
declarations & definitions that you can use to get this information.

1) The function WinStationQueryInformationW() should be accessed
dynamically via the use of LoadLibrary() and GetProcAddress(). Towards that
end, there's a type definition for a pointer-to-a-function.

2) The system console session cannot go into an idle/disconnected state.
As such, the LastInputTime value will always math CurrentTime for the
console session.

3) The LastInputTime value will be zero if the session has gone
disconnected. In that case, use the DisconnectTime value in place of
LastInputTime when calculating the current idle time for a disconnected session.

4) All of these time values are GMT time values.

5) The disconnect time value will be zero if the sesson has never been
disconnected.

#define LOGONID_CURRENT ((ULONG)-1)
#define SERVERNAME_CURRENT ((HANDLE)NULL)

typedef enum _WINSTATIONINFOCLASS {
WinStationInformation = 8
} WINSTATIONINFOCLASS;

typedef struct _WINSTATIONINFORMATIONW {
BYTE Reserved1[72];
ULONG SessionId;
BYTE Reserved2[4];
FILETIME ConnectTime;
FILETIME DisconnectTime;
FILETIME LastInputTime;
FILETIME LoginTime;
BYTE Reserved3[1096];
FILETIME CurrentTime;
} WINSTATIONINFORMATIONW, * PWINSTATIONINFORMATIONW;

typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)(
HANDLE, ULONG, WINSTATIONINFOCLASS, PVOID, ULONG, PULONG );

BOOL Result;
HANDLE hServer = NULL;
HANDLE hWinSta = NULL;
ULONG SessId;
ULONG BufLen;
ULONG RetLen;
WINSTATIONINFORMATION Buf;
PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW = NULL;

hWinSta = LoadLibrary("WINSTA.DLL");

WinStatonQueryInformationW =
GetProcAddress(hWinSta,"WinStationQueryInformatoinW");

BufLen = sizeof(Buf);

// Assume that hServer is a valid server handle previously obtained from
// WTSOpenServer().
//
// Assume that SessId has been set to the desired session id value. The
// term "logon id" is synonymous with "session id".

Result =
WinStationQueryInformationW(hServer,SessId,WinStationInformation,&Buf,BufLen,&RetLen);

if (Result)
{
// Use the SYSTEMTIME structure and the FileTimeToSystemTime() function
// to convert from FILETIME to SYSTEMTIME format. Remember, these time
// values are GMT values; they don't have the local time zone offset
// applied to them.
}
{
// handle the error

Reply all
Reply to author
Forward
0 new messages