[python-win32] Need a value from pywin32
Eryk Sun
eryksun at gmail.com
Wed Jun 22 16:27:59 EDT 2022
On 6/21/22, Steven Manross <steven at manross.net> 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()).
More information about the python-win32
mailing list