Skip to content

Commit eb131d2

Browse files
committed
system.services now handle int/slice for getitem + update doc + add a sample
1 parent 042e77a commit eb131d2

3 files changed

Lines changed: 42 additions & 20 deletions

File tree

docs/source/sample.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ Output
9292
.. literalinclude:: samples_output\system.txt
9393

9494

95+
.. _sample_services_demo:
96+
97+
Services
98+
""""""""
99+
100+
.. literalinclude:: ..\..\samples\service\service_demo.py
101+
102+
Output
103+
104+
.. literalinclude:: samples_output\service_service_demo.txt
105+
106+
107+
108+
95109
.. _sample_network_exploration:
96110

97111
:class:`Network` - socket exploration

docs/source/service.rst

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,12 @@ Service
44
The list of services is accessible via :py:attr:`windows.system.services
55
<windows.winobject.system.System.services>`
66

7-
87
.. note::
98

10-
See sample :ref:`sample_system`
9+
See sample :ref:`sample_system` & :ref:`sample_services_demo`
1110

1211
.. module:: windows.winobject.service
1312

14-
.. autoclass:: ServiceStatus
15-
:exclude-members: count, index
16-
17-
.. autoclass:: ServiceA
13+
.. autoclass:: Service
1814
:show-inheritance:
1915
:inherited-members:

windows/winobject/service.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
from contextlib import contextmanager
66

77
from windows import utils
8+
from windows.pycompat import int_types
89
import windows.generated_def as gdef
910
from windows.generated_def import *
1011
from windows import security
1112
from windows.pycompat import basestring
1213

13-
# TODO: RM :)
14-
ServiceStatus = namedtuple("ServiceStatus", ["type", "state", "control_accepted", "flags"])
1514
"""
1615
``type`` might be one of:
1716
@@ -40,17 +39,24 @@
4039

4140

4241
class ServiceManager(utils.AutoHandle):
43-
_close_function = staticmethod(windows.winproxy.CloseServiceHandle)
44-
4542
def _get_handle(self):
4643
return windows.winproxy.OpenSCManagerA(dwDesiredAccess=gdef.MAXIMUM_ALLOWED)
4744

4845
def open_service(self, name, access=gdef.MAXIMUM_ALLOWED):
4946
return windows.winproxy.OpenServiceA(self.handle, name, access) # Check service exists :)
5047

51-
def get_service(self, name, access=gdef.MAXIMUM_ALLOWED):
52-
handle = self.open_service(name, access)
53-
return NewService(name=name, handle=handle)
48+
def get_service(self, key, access=gdef.MAXIMUM_ALLOWED):
49+
if isinstance(key, int_types):
50+
return self.enumerate_services()[key]
51+
if isinstance(key, slice):
52+
# Get service list
53+
servlist = self.enumerate_services()
54+
# Extract indexes matching the slice
55+
indexes = key.indices(len(servlist))
56+
return [servlist[idx] for idx in range(*indexes)]
57+
# Retrieve service by its name
58+
handle = self.open_service(key, access)
59+
return Service(name=key, handle=handle)
5460

5561
__getitem__ = get_service
5662

@@ -83,7 +89,7 @@ def _enumerate_services_generator(self):
8389
services_array = (gdef.ENUM_SERVICE_STATUS_PROCESSA * nb_services.value).from_buffer(buffer)
8490
for service_info in services_array:
8591
shandle = self.open_service(service_info.lpServiceName)
86-
yield NewService(handle=shandle, name=service_info.lpServiceName, description=service_info.lpDisplayName)
92+
yield Service(handle=shandle, name=service_info.lpServiceName, description=service_info.lpDisplayName)
8793
return
8894

8995
__iter__ = _enumerate_services_generator
@@ -92,11 +98,9 @@ def enumerate_services(self):
9298
return list(self._enumerate_services_generator())
9399

94100

95-
class NewService(gdef.SC_HANDLE):
96-
# close_function = windows.winproxy.CloseServiceHandle
97-
101+
class Service(gdef.SC_HANDLE):
98102
def __init__(self, handle, name, description=None):
99-
super(NewService, self).__init__(handle)
103+
super(Service, self).__init__(handle)
100104
self.name = name
101105
"""The name of the service
102106
@@ -115,12 +119,16 @@ def description(self):
115119

116120
@property
117121
def status(self):
122+
"""The status of the service
123+
124+
:type: :class:`~windows.generated_def.winstructs.SERVICE_STATUS_PROCESS`
125+
"""
118126
buffer = windows.utils.BUFFER(gdef.SERVICE_STATUS_PROCESS)()
119127
size_needed = gdef.DWORD()
120128
windows.winproxy.QueryServiceStatusEx(self, gdef.SC_STATUS_PROCESS_INFO, buffer.cast(gdef.LPBYTE), ctypes.sizeof(buffer), size_needed)
121129
return buffer[0]
122130

123-
@utils.fixedpropety
131+
@property # Can change if service is started/stopped when the object exist
124132
def process(self):
125133
"""The process running the service (if any)
126134
@@ -134,6 +142,10 @@ def process(self):
134142

135143
@property
136144
def security_descriptor(self):
145+
"""The security descriptor of the service
146+
147+
:type: :class:`~windows.security.SecurityDescriptor`
148+
"""
137149
return security.SecurityDescriptor.from_service(self.name)
138150

139151
def start(self, args=None):
@@ -151,7 +163,7 @@ def stop(self):
151163
return status
152164

153165
def __repr__(self):
154-
return """<{0} "{1}" {2}>""".format(type(self).__name__, self.name, self.status.state)
166+
return """<{0} "{1}" {2!r}>""".format(type(self).__name__, self.name, self.status.state)
155167

156168
def __del__(self):
157169
return windows.winproxy.CloseServiceHandle(self)

0 commit comments

Comments
 (0)