使用 ctypes 实现 Windows 服务。未调用 ServiceCtrl 处理程序
Implementing a Windows Service with ctypes. ServiceCtrl handler not called
我正在尝试使用 ctypes 在 Python 中实施 Windows 服务。
import ctypes
import logging
import logging.config
import threading
import six
logger = logging.getLogger("service3")
SERVICE_MAIN = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_uint32)
HANDLER_FUNCTION = ctypes.WINFUNCTYPE(ctypes.c_uint32, ctypes.c_uint32)
class ServiceTable (ctypes.Structure):
_fields_ = [("serviceName", ctypes.c_char_p),
("serviceProc", SERVICE_MAIN),
("serviceNameTerm", ctypes.c_char_p),
("serviceProcTerm", ctypes.c_void_p)]
class ServiceStatus (ctypes.Structure):
_fields_ = [("dwServiceType", ctypes.c_uint32),
("dwCurrentState", ctypes.c_uint32),
("dwControlsAccepted", ctypes.c_uint32),
("dwWin32ExitCode", ctypes.c_uint32),
("dwServiceSpecificExitCode", ctypes.c_uint32),
("dwCheckPoint", ctypes.c_uint32),
("dwWaitHint", ctypes.c_uint32)]
advapi32 = ctypes.windll.advapi32
kernel32 = ctypes.windll.kernel32
advapi32.StartServiceCtrlDispatcherA.argtypes = [ctypes.POINTER(ServiceTable)]
StartServiceCtrlDispatcherA = advapi32.StartServiceCtrlDispatcherA
advapi32.SetServiceStatus.argtypes = [ctypes.c_void_p, ctypes.POINTER(ServiceStatus)]
SetServiceStatus = advapi32.SetServiceStatus
advapi32.RegisterServiceCtrlHandlerA.argtypes = [ctypes.c_char_p, HANDLER_FUNCTION]
advapi32.RegisterServiceCtrlHandlerA.restype = ctypes.c_void_p
RegisterServiceCtrlHandlerA = advapi32.RegisterServiceCtrlHandlerA
SERVICE_WIN32_OWN_PROCESS = 0x10
SERVICE_ACCEPT_STOP = 0x1
SERVICE_CONTROL_STOP = 0x1
SERVICE_RUNNING = 0x4
SERVICE_STOPPED = 0x1
SERVICE_STOP_PENDING = 0x3
class Service:
serviceName = "RSJTest"
ServiceStatusHandle = None
def __init__(self):
self.TerminateEvent = threading.Event()
def StartMain(self):
try:
logger.debug("ServiceMain")
self.serviceProc = SERVICE_MAIN(self.StartMain2)
self.serviceTable = ServiceTable(serviceName=self.encode(self.serviceName), serviceProc=self.serviceProc)
StartServiceCtrlDispatcherA(self.serviceTable)
except:
logger.exception("ServiceMain")
def StartMain2(self, argC):
try:
logger.debug("StartMain2 %d", argC)
self.handlerProc = HANDLER_FUNCTION(self.HandlerProc)
self.ServiceStatusHandle = RegisterServiceCtrlHandlerA( self.encode(self.serviceName), self.handlerProc)
logger.debug("ServiceStatusHandle %xd", self.ServiceStatusHandle)
self.SetServiceStatus(SERVICE_RUNNING)
self.Start()
logger.debug("Start returned")
self.SetServiceStatus(SERVICE_STOPPED)
except:
logger.exception("StartMain2")
return 0
def Start(self):
self.TerminateEvent.wait()
def Stop(self):
self.TerminateEvent.set()
def HandlerProc(self, dwControl):
try:
logger.debug("HandlerProc")
if dwControl == SERVICE_CONTROL_STOP:
self.SetServiceStatus(SERVICE_STOP_PENDING)
self.Stop()
except:
logger.exception("HandlerProc")
return 0
def SetServiceStatus(self, newStatus):
serviceStatus = ServiceStatus(dwServiceType=SERVICE_WIN32_OWN_PROCESS,
dwCurrentState=newStatus,
dwControlsAccepted=SERVICE_ACCEPT_STOP)
ret = SetServiceStatus(self.ServiceStatusHandle, serviceStatus)
logger.debug("SetServiceStatus returned %d", ret)
def encode(self, stringParm):
if stringParm == None:
return None
return six.ensure_binary(stringParm)
logConfig = {
"version": 1,
"disable_existing_loggers": False,
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"]
}
},
"handlers": {
"file": {
"class": "logging.handlers.TimedRotatingFileHandler",
"formatter": "precise",
"filename": "c:\temp\service.log",
"when": "midnight",
"backupCount": 30,
"level": "NOTSET"
}
},
"formatters": {
"precise": {
"format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
}
}
def main():
logging.config.dictConfig(logConfig)
logger.debug("started")
service = Service()
service.StartMain()
if __name__ == "__main__":
main()
我可以毫无问题地启动我的服务(例如从服务管理器)。
我也可以停止我的服务(从服务管理器)但收到错误 1061:
- 我的 HandlerProc 没有被调用(至少没有被记录)
- 服务进程终止
- 我得到 1062 我尝试再次停止服务
注意:从 StartMain2 调用 self.handlerProc(0) 会调用 ServiceCtrlHandler
怎么了?
我在 Windows 10.
上进行了测试
在用 RegisterServiceCtrlHandlerExA 替换 RegisterServiceCtrlHandlerA 之后(并在方法调用中包含附加参数(和 HANDLER_FUNCTION),一切都按预期工作。
HANDLER_FUNCTION_EX = ctypes.WINFUNCTYPE(ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p)
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [ctypes.c_char_p, HANDLER_FUNCTION_EX, ctypes.c_void_p]
advapi32.RegisterServiceCtrlHandlerExA.restype = ctypes.c_void_p
RegisterServiceCtrlHandlerExA = advapi32.RegisterServiceCtrlHandlerExA
...
self.handlerProcEx = HANDLER_FUNCTION_EX(self.HandlerProcEx)
self.ServiceStatusHandle = RegisterServiceCtrlHandlerExA(self.encode(self.serviceName), self.handlerProcEx, None)
...
def HandlerProcEx(self, dwControl, dwEventType, lpEventData, lpContext):
...
我正在尝试使用 ctypes 在 Python 中实施 Windows 服务。
import ctypes
import logging
import logging.config
import threading
import six
logger = logging.getLogger("service3")
SERVICE_MAIN = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_uint32)
HANDLER_FUNCTION = ctypes.WINFUNCTYPE(ctypes.c_uint32, ctypes.c_uint32)
class ServiceTable (ctypes.Structure):
_fields_ = [("serviceName", ctypes.c_char_p),
("serviceProc", SERVICE_MAIN),
("serviceNameTerm", ctypes.c_char_p),
("serviceProcTerm", ctypes.c_void_p)]
class ServiceStatus (ctypes.Structure):
_fields_ = [("dwServiceType", ctypes.c_uint32),
("dwCurrentState", ctypes.c_uint32),
("dwControlsAccepted", ctypes.c_uint32),
("dwWin32ExitCode", ctypes.c_uint32),
("dwServiceSpecificExitCode", ctypes.c_uint32),
("dwCheckPoint", ctypes.c_uint32),
("dwWaitHint", ctypes.c_uint32)]
advapi32 = ctypes.windll.advapi32
kernel32 = ctypes.windll.kernel32
advapi32.StartServiceCtrlDispatcherA.argtypes = [ctypes.POINTER(ServiceTable)]
StartServiceCtrlDispatcherA = advapi32.StartServiceCtrlDispatcherA
advapi32.SetServiceStatus.argtypes = [ctypes.c_void_p, ctypes.POINTER(ServiceStatus)]
SetServiceStatus = advapi32.SetServiceStatus
advapi32.RegisterServiceCtrlHandlerA.argtypes = [ctypes.c_char_p, HANDLER_FUNCTION]
advapi32.RegisterServiceCtrlHandlerA.restype = ctypes.c_void_p
RegisterServiceCtrlHandlerA = advapi32.RegisterServiceCtrlHandlerA
SERVICE_WIN32_OWN_PROCESS = 0x10
SERVICE_ACCEPT_STOP = 0x1
SERVICE_CONTROL_STOP = 0x1
SERVICE_RUNNING = 0x4
SERVICE_STOPPED = 0x1
SERVICE_STOP_PENDING = 0x3
class Service:
serviceName = "RSJTest"
ServiceStatusHandle = None
def __init__(self):
self.TerminateEvent = threading.Event()
def StartMain(self):
try:
logger.debug("ServiceMain")
self.serviceProc = SERVICE_MAIN(self.StartMain2)
self.serviceTable = ServiceTable(serviceName=self.encode(self.serviceName), serviceProc=self.serviceProc)
StartServiceCtrlDispatcherA(self.serviceTable)
except:
logger.exception("ServiceMain")
def StartMain2(self, argC):
try:
logger.debug("StartMain2 %d", argC)
self.handlerProc = HANDLER_FUNCTION(self.HandlerProc)
self.ServiceStatusHandle = RegisterServiceCtrlHandlerA( self.encode(self.serviceName), self.handlerProc)
logger.debug("ServiceStatusHandle %xd", self.ServiceStatusHandle)
self.SetServiceStatus(SERVICE_RUNNING)
self.Start()
logger.debug("Start returned")
self.SetServiceStatus(SERVICE_STOPPED)
except:
logger.exception("StartMain2")
return 0
def Start(self):
self.TerminateEvent.wait()
def Stop(self):
self.TerminateEvent.set()
def HandlerProc(self, dwControl):
try:
logger.debug("HandlerProc")
if dwControl == SERVICE_CONTROL_STOP:
self.SetServiceStatus(SERVICE_STOP_PENDING)
self.Stop()
except:
logger.exception("HandlerProc")
return 0
def SetServiceStatus(self, newStatus):
serviceStatus = ServiceStatus(dwServiceType=SERVICE_WIN32_OWN_PROCESS,
dwCurrentState=newStatus,
dwControlsAccepted=SERVICE_ACCEPT_STOP)
ret = SetServiceStatus(self.ServiceStatusHandle, serviceStatus)
logger.debug("SetServiceStatus returned %d", ret)
def encode(self, stringParm):
if stringParm == None:
return None
return six.ensure_binary(stringParm)
logConfig = {
"version": 1,
"disable_existing_loggers": False,
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"]
}
},
"handlers": {
"file": {
"class": "logging.handlers.TimedRotatingFileHandler",
"formatter": "precise",
"filename": "c:\temp\service.log",
"when": "midnight",
"backupCount": 30,
"level": "NOTSET"
}
},
"formatters": {
"precise": {
"format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
}
}
def main():
logging.config.dictConfig(logConfig)
logger.debug("started")
service = Service()
service.StartMain()
if __name__ == "__main__":
main()
我可以毫无问题地启动我的服务(例如从服务管理器)。 我也可以停止我的服务(从服务管理器)但收到错误 1061:
- 我的 HandlerProc 没有被调用(至少没有被记录)
- 服务进程终止
- 我得到 1062 我尝试再次停止服务
注意:从 StartMain2 调用 self.handlerProc(0) 会调用 ServiceCtrlHandler
怎么了?
我在 Windows 10.
上进行了测试在用 RegisterServiceCtrlHandlerExA 替换 RegisterServiceCtrlHandlerA 之后(并在方法调用中包含附加参数(和 HANDLER_FUNCTION),一切都按预期工作。
HANDLER_FUNCTION_EX = ctypes.WINFUNCTYPE(ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p)
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [ctypes.c_char_p, HANDLER_FUNCTION_EX, ctypes.c_void_p]
advapi32.RegisterServiceCtrlHandlerExA.restype = ctypes.c_void_p
RegisterServiceCtrlHandlerExA = advapi32.RegisterServiceCtrlHandlerExA
...
self.handlerProcEx = HANDLER_FUNCTION_EX(self.HandlerProcEx)
self.ServiceStatusHandle = RegisterServiceCtrlHandlerExA(self.encode(self.serviceName), self.handlerProcEx, None)
...
def HandlerProcEx(self, dwControl, dwEventType, lpEventData, lpContext):
...