Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Steven Manross
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  
Sent: Wednesday, June 22, 2022 1:28 PM
To: Steven Manross 
Cc: python-win32@python.org
Subject: Re: [python-win32] Need a value from pywin32

On 6/21/22, Steven Manross  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),
   

Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Eryk Sun
On 6/21/22, Steven Manross  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, 

Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Steven Manross
Thanks a lot for the help!!!

This is no longer Excepting...  But the Result is 0 and there doesn't seem to 
be any data in the Buf structure or indication that there were results in 
RtnLen...  I get to debug this more..  YAY!!!

Steven
-Original Message-
From: python-win32  On 
Behalf Of Tim Roberts
Sent: Tuesday, June 21, 2022 10:04 PM
To: python-win32@python.org
Subject: Re: [python-win32] Need a value from pywin32

On 6/21/22 13:39, Steven Manross wrote:

> I was intrigued by this and I would like to get it to work, but I cannot...  
> I know I'm doing something wrong, but don't know what.  I will leave this for 
> the archives, and maybe it will help someone else some day.
> ...
> def get_wts_info(session_id):
>  '''
>  Get WTS Info
>  '''
>  # This only tries to work on the local server currently but I get 
> an access violation running the WinStationQueryInformationW line
>
>  Buf = ctypes.POINTER(WinStationInformation)()
>  BufLen = 260
>
>  hWinSta = ctypes.windll.LoadLibrary("WINSTA.DLL")
>  if hWinSta:
>  winsta_handle = hWinSta._handle
>  print(f'winsta_handle = {winsta_handle}')
>  QueryInfoHandle = 
> ctypes.windll.kernel32.GetProcAddress(ctypes.c_ulonglong(winsta_handle
> ), b"WinStationQueryInformationW")
>
>  # This handle is 0...  possibly because of the numeric 
> conversion from the winsta_handle to a ctypes.c_ulonglong  ???  unsure

No, 0 is the error return that means the name was not found.

You shouldn't need to use LoadLibrary and GetProcAddress.  ctypes does that for 
you automatically.

     winsta = ctypes.WinDLL('winsta.dll')

     winsta.WinStationQueryInformationW( 0, session_id, 8, ctypes.byref(Buf), 
BufLen, ctypes.byref(RtnLen))

If you have Visual Studio, you can try doing "link /dump /exports 
\windows\system32\winsta.dll" to make sure it has that entry point.

--
Tim Roberts, t...@probo.com
Providenza & Boekelheide, Inc.

___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32
___
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32