We have a winner!
Huge thanks from me even though I wasn’t the OP because I've wanted to know how
to do this for a while and just started to get my feet wet in this arena!!! I
now have a VERY GOOD EXAMPLE of how to start looking at doing a complex task
like this with all the nested references. UGH!
In [16]: get_idle_time(2) # session id = 2
Out[16]: 0.0156271
Please note that line wraps (and or a missing newline) in the previous email
may cause copy/paste issues in Eryk's code around these lines:
winsta.WinStationQueryInformationW.restype = wintypes.BOOLEAN
# this needs to be a newline
winsta.WinStationQueryInformationW.argtypes = (
wintypes.HANDLE, # ServerHandle
wintypes.ULONG, # SessionId
ctypes.c_long, # WinStationInformationClass
wintypes.LPVOID, # pWinStationInformation
wintypes.ULONG, # WinStationInformationLength
wintypes.PULONG, # pReturnLength
)
I HOPE THIS HELPS AND THANK YOU VERY MUCH!
Steven
-----Original Message-----
From: Eryk Sun <[email protected]>
Sent: Wednesday, June 22, 2022 1:28 PM
To: Steven Manross <[email protected]>
Cc: [email protected]
Subject: Re: [python-win32] Need a value from pywin32
On 6/21/22, Steven Manross <[email protected]> wrote:
>
> class WinStationInformation(ctypes.Structure):
> __fields__ = [
> ('ConnectState', ctypes.c_long),
> ('WinStationName', ctypes.wintypes.WCHAR),
> ('LogonId', ctypes.c_ulong),
> ('ConnectTime', ctypes.wintypes.LARGE_INTEGER),
> ('DisconnectTime', ctypes.wintypes.LARGE_INTEGER),
> ('LastInputTime', ctypes.wintypes.LARGE_INTEGER),
> ('LogonTime', ctypes.wintypes.LARGE_INTEGER),
> ('Status', ctypes.c_int()),
> ('Domain', ctypes.wintypes.WCHAR * (17 + 1)),
> ('UserName', ctypes.wintypes.WCHAR * (20 + 1)),
> ('CurrentTime', ctypes.wintypes.LARGE_INTEGER),
> ]
The above definition is incorrect for `WinStationName` and `Status`.
Defining the PROTOCOLSTATUS type for `Status` is tedious. Note also that the
ctypes attribute to set is `_fields_`, not `__fields__`, so the above struct is
actually defined with no fields (i.e. zero size).
Here's an example that defines a get_idle_time() function, based on the
difference between the current time and the last input time in the session.
import ctypes
from ctypes import wintypes
winsta = ctypes.WinDLL('winsta', use_last_error=True)
WINSTATIONNAME_LENGTH = 32
DOMAIN_LENGTH = 17
USERNAME_LENGTH = 20
MAX_THINWIRECACHE = 4
SERVERNAME_CURRENT = None
LOGONID_CURRENT = -1
# WINSTATIONINFOCLASS
WinStationInformation = 8
# WINSTATIONSTATECLASS
State_Active = 0
State_Connected = 1
State_ConnectQuery = 2
State_Shadow = 3
State_Disconnected = 4
State_Idle = 5
State_Listen = 6
State_Reset = 7
State_Down = 8
State_Init = 9
class TSHARE_COUNTERS(ctypes.Structure):
__slots__ = ()
_fields_ = (
('Reserved', wintypes.ULONG),
)
class PROTOCOLCOUNTERS(ctypes.Structure):
__slots__ = ()
class SPECIFIC(ctypes.Union):
__slots__ = ()
_fields_ = (
('TShareCounters', TSHARE_COUNTERS),
('Reserved', wintypes.ULONG * 100),
)
_fields_ = (
('WdBytes', wintypes.ULONG),
('WdFrames', wintypes.ULONG),
('WaitForOutBuf', wintypes.ULONG),
('Frames', wintypes.ULONG),
('Bytes', wintypes.ULONG),
('CompressedBytes', wintypes.ULONG),
('CompressFlushes', wintypes.ULONG),
('Errors', wintypes.ULONG),
('Timeouts', wintypes.ULONG),
('AsyncFramingError', wintypes.ULONG),
('AsyncOverrunError', wintypes.ULONG),
('AsyncOverflowError', wintypes.ULONG),
('AsyncParityError', wintypes.ULONG),
('TdErrors', wintypes.ULONG),
('ProtocolType', wintypes.USHORT),
('Length', wintypes.USHORT),
('Specific', SPECIFIC),
)
class THINWIRECACHE (ctypes.Structure):
__slots__ = ()
_fields_ = (
('CacheReads', wintypes.ULONG),
('CacheHits', wintypes.ULONG),
)
class RESERVED_CACHE(ctypes.Structure):
__slots__ = ()
_fields_ = (
('ThinWireCache[', THINWIRECACHE * MAX_THINWIRECACHE),
)
class CACHE_STATISTICS(ctypes.Structure):
__slots__ = ()
class SPECIFIC(ctypes.Union):
__slots__ = ()
_fields_ = (
('ReservedCacheStats', RESERVED_CACHE),
('TShareCacheStats', wintypes.ULONG),
('Reserved', wintypes.ULONG * 20),
)
_fields_ = (
('ProtocolType', wintypes.USHORT),
('Length', wintypes.USHORT),
('Specific', SPECIFIC),
)
class PROTOCOLSTATUS(ctypes.Structure):
__slots__ = ()
_fields_ = (
('Output', PROTOCOLCOUNTERS),
('Input', PROTOCOLCOUNTERS),
('Cache', CACHE_STATISTICS),
('AsyncSignal', wintypes.ULONG),
('AsyncSignalMask', wintypes.ULONG),
)
class WINSTATIONINFORMATION(ctypes.Structure):
__slots__ = ()
_fields_ = (
('ConnectState', ctypes.c_long),
('WinStationName', wintypes.WCHAR * (WINSTATIONNAME_LENGTH + 1)),
('LogonId', wintypes.ULONG),
('ConnectTime', wintypes.LARGE_INTEGER),
('DisconnectTime', wintypes.LARGE_INTEGER),
('LastInputTime', wintypes.LARGE_INTEGER),
('LogonTime', wintypes.LARGE_INTEGER),
('Status', PROTOCOLSTATUS),
('Domain', wintypes.WCHAR * (DOMAIN_LENGTH + 1)),
('UserName', wintypes.WCHAR * (USERNAME_LENGTH + 1)),
('CurrentTime', wintypes.LARGE_INTEGER)
)
winsta.WinStationQueryInformationW.restype = wintypes.BOOLEAN
winsta.WinStationQueryInformationW.argtypes = (
wintypes.HANDLE, # ServerHandle
wintypes.ULONG, # SessionId
ctypes.c_long, # WinStationInformationClass
wintypes.LPVOID, # pWinStationInformation
wintypes.ULONG, # WinStationInformationLength
wintypes.PULONG, # pReturnLength
)
def get_idle_time(session_id=LOGONID_CURRENT,
server_handle=SERVERNAME_CURRENT):
info = WINSTATIONINFORMATION()
rlen = wintypes.ULONG()
if not winsta.WinStationQueryInformationW(
server_handle, session_id, WinStationInformation,
ctypes.byref(info), ctypes.sizeof(info), ctypes.byref(rlen)):
raise ctypes.WinError(ctypes.get_last_error())
if info.ConnectState == State_Disconnected:
last_input_time = info.DisconnectTime
else:
last_input_time = info.LastInputTime
if not last_input_time:
return None
return (info.CurrentTime - last_input_time) / 1e7
---
Note that the `winsta` WinDLL instance is configured to capture the last error
value (i.e. use_last_error=True). Thus if
WinStationQueryInformationW() fails, the relevant OSError exception is
ctypes.WinError(ctypes.get_last_error()).
_______________________________________________
python-win32 mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-win32