Python: advapi32.SetServiceStatus() fails with error 6
Original issue is now resolved, many thanks to eryksun.
Fixed code is below, I now have a different issue that I will ask about in another thread if I cannot figure it out.
Error 6 is invalid handle, however, the handle appears to be good, I believe the error is coming from the second parameter.
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
Note: if I make the pointer None, then it doesn't fail (but obviously doesn't do anything useful either).
python -V
Python 3.6.6
Larger snippet:
from ctypes import *
from ctypes.wintypes import *
winKernel = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
global g_ServiceName
g_ServiceName = "StatusMonitor"
global g_lpcstrServiceName
g_lpcstrServiceName = LPCSTR(b"StatusMonitor")
class _SERVICE_STATUS(Structure):
_pack_ = 4
_fields_ = [
("dwServiceType", DWORD),
("dwCurrentState", DWORD),
("dwControlsAccepted", DWORD),
("dwWin32ExitCode", DWORD),
("dwServiceSpecificExitCode", DWORD),
("dwCheckPoint", DWORD),
("dwWaitHint", DWORD)
]
LPSERVICE_STATUS = POINTER(_SERVICE_STATUS)
global m_oServiceStatus
m_oServiceStatus = _SERVICE_STATUS(0, 0, 0, 0, 0, 0, 0)
global g_hServiceStatus
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
<lots of code snipped>
def status_report(dwCurrentState, dwWin32ExitCode, dwWaitHint):
global g_dwCheckPoint
global g_isService
try:
# Fill in the SERVICE_STATUS structure.
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
m_oServiceStatus.dwCurrentState = dwCurrentState
m_oServiceStatus.dwWin32ExitCode = dwWin32ExitCode
m_oServiceStatus.dwWaitHint = dwWaitHint
if dwCurrentState == SERVICE_START_PENDING:
m_oServiceStatus.dwControlsAccepted = 0
else:
m_oServiceStatus.dwControlsAccepted = 1
if (dwCurrentState == SERVICE_STOPPED) or (dwCurrentState == SERVICE_RUNNING):
m_oServiceStatus.dwCheckPoint = 0
else:
g_dwCheckPoint += 1
m_oServiceStatus.dwCheckPoint = g_dwCheckPoint
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
#logging.info("SetServiceStatus(" + str(g_hServiceStatus) + ", status=" + str(dwStatus) + ")")
logging.info("status_report(" + str(g_hServiceStatus) + ", " + str(dwCurrentState) + ", " + str(dwWin32ExitCode) + ", " + str(dwWaitHint) + ")")
dwStatus = None
if g_isService:
# Report the status of the service to the SCM.
ptrServiceStatus = LPSERVICE_STATUS(m_oServiceStatus)
logging.info("m_oServiceStatus struct: " + str(m_oServiceStatus) + ", ref: " + str(byref(m_oServiceStatus)))
logging.info(" " + "ptr: " + str(str(pointer(m_oServiceStatus))) + " PTR: " + str(ptrServiceStatus))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
if 0 == status:
dwStatus = ctypes.get_last_error()
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
logging.error("status_report " + str(e) + " line: " + str(exc_tb.tb_lineno))
return dwStatus
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
logging.info("control handler " + str(g_hServiceStatus))
logging.info("control handler called count " + str(g_nServiceControlHandlerCalled))
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_oServiceStatus.dwServiceSpecificExitCode = 0;
# set the service state as pending
dwStatus = status_report(SERVICE_START_PENDING, NO_ERROR, 3000);
logging.info("service_main: status_report(" + str(g_hServiceStatus) + "), status=" + str(dwStatus))
log_service_status(m_oServiceStatus)
Updated logging result:
INFO service_start
INFO service_start: StopEventHandle 952
INFO service_main called JimsStatusMonitor control handler called count 0
INFO control handler 2787686645712
INFO control handler called count 0
INFO status_report(2787686645712, 2, 0, 3000)128
INFO m_oServiceStatus struct: <__main__._SERVICE_STATUS object at 0x000002890FC666C8>, ref: <cparam 'P' (000002890FCA8A30)>
INFO ptr: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66848> PTR: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66648>
INFO service_main: status_report(2787686645712), status=None
INFO 16, 2, 0, 0, 0, 1, 3000
I must be missing something obvious, but I don't see it. I tried different pack to the structure, but with no improvement.
I also tried using byref() instead of pointer() and just passing the structure, but none of those worked. I believe using pointer() is correct here because there is another API to set the dispatch table that is working using pointer().
Note that I am specifically using FFI for this as I found the existing packages lacking for what I am trying to do. This Python solution is based on a C++ solution that I wrote that works, I just need to understand whatever nuance to the FFI that is causing it to fail.
I should add that the service is actually running at this point, I just can't transition it out of Starting state with this issue.
Hopefully someone can tell me what I am doing wrong?
Thanks in advance,
-Dave
python windows service ffi
|
show 5 more comments
Original issue is now resolved, many thanks to eryksun.
Fixed code is below, I now have a different issue that I will ask about in another thread if I cannot figure it out.
Error 6 is invalid handle, however, the handle appears to be good, I believe the error is coming from the second parameter.
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
Note: if I make the pointer None, then it doesn't fail (but obviously doesn't do anything useful either).
python -V
Python 3.6.6
Larger snippet:
from ctypes import *
from ctypes.wintypes import *
winKernel = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
global g_ServiceName
g_ServiceName = "StatusMonitor"
global g_lpcstrServiceName
g_lpcstrServiceName = LPCSTR(b"StatusMonitor")
class _SERVICE_STATUS(Structure):
_pack_ = 4
_fields_ = [
("dwServiceType", DWORD),
("dwCurrentState", DWORD),
("dwControlsAccepted", DWORD),
("dwWin32ExitCode", DWORD),
("dwServiceSpecificExitCode", DWORD),
("dwCheckPoint", DWORD),
("dwWaitHint", DWORD)
]
LPSERVICE_STATUS = POINTER(_SERVICE_STATUS)
global m_oServiceStatus
m_oServiceStatus = _SERVICE_STATUS(0, 0, 0, 0, 0, 0, 0)
global g_hServiceStatus
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
<lots of code snipped>
def status_report(dwCurrentState, dwWin32ExitCode, dwWaitHint):
global g_dwCheckPoint
global g_isService
try:
# Fill in the SERVICE_STATUS structure.
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
m_oServiceStatus.dwCurrentState = dwCurrentState
m_oServiceStatus.dwWin32ExitCode = dwWin32ExitCode
m_oServiceStatus.dwWaitHint = dwWaitHint
if dwCurrentState == SERVICE_START_PENDING:
m_oServiceStatus.dwControlsAccepted = 0
else:
m_oServiceStatus.dwControlsAccepted = 1
if (dwCurrentState == SERVICE_STOPPED) or (dwCurrentState == SERVICE_RUNNING):
m_oServiceStatus.dwCheckPoint = 0
else:
g_dwCheckPoint += 1
m_oServiceStatus.dwCheckPoint = g_dwCheckPoint
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
#logging.info("SetServiceStatus(" + str(g_hServiceStatus) + ", status=" + str(dwStatus) + ")")
logging.info("status_report(" + str(g_hServiceStatus) + ", " + str(dwCurrentState) + ", " + str(dwWin32ExitCode) + ", " + str(dwWaitHint) + ")")
dwStatus = None
if g_isService:
# Report the status of the service to the SCM.
ptrServiceStatus = LPSERVICE_STATUS(m_oServiceStatus)
logging.info("m_oServiceStatus struct: " + str(m_oServiceStatus) + ", ref: " + str(byref(m_oServiceStatus)))
logging.info(" " + "ptr: " + str(str(pointer(m_oServiceStatus))) + " PTR: " + str(ptrServiceStatus))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
if 0 == status:
dwStatus = ctypes.get_last_error()
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
logging.error("status_report " + str(e) + " line: " + str(exc_tb.tb_lineno))
return dwStatus
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
logging.info("control handler " + str(g_hServiceStatus))
logging.info("control handler called count " + str(g_nServiceControlHandlerCalled))
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_oServiceStatus.dwServiceSpecificExitCode = 0;
# set the service state as pending
dwStatus = status_report(SERVICE_START_PENDING, NO_ERROR, 3000);
logging.info("service_main: status_report(" + str(g_hServiceStatus) + "), status=" + str(dwStatus))
log_service_status(m_oServiceStatus)
Updated logging result:
INFO service_start
INFO service_start: StopEventHandle 952
INFO service_main called JimsStatusMonitor control handler called count 0
INFO control handler 2787686645712
INFO control handler called count 0
INFO status_report(2787686645712, 2, 0, 3000)128
INFO m_oServiceStatus struct: <__main__._SERVICE_STATUS object at 0x000002890FC666C8>, ref: <cparam 'P' (000002890FCA8A30)>
INFO ptr: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66848> PTR: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66648>
INFO service_main: status_report(2787686645712), status=None
INFO 16, 2, 0, 0, 0, 1, 3000
I must be missing something obvious, but I don't see it. I tried different pack to the structure, but with no improvement.
I also tried using byref() instead of pointer() and just passing the structure, but none of those worked. I believe using pointer() is correct here because there is another API to set the dispatch table that is working using pointer().
Note that I am specifically using FFI for this as I found the existing packages lacking for what I am trying to do. This Python solution is based on a C++ solution that I wrote that works, I just need to understand whatever nuance to the FFI that is causing it to fail.
I should add that the service is actually running at this point, I just can't transition it out of Starting state with this issue.
Hopefully someone can tell me what I am doing wrong?
Thanks in advance,
-Dave
python windows service ffi
Useadvapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
andctypes.get_last_error()
instead ofGetLastError()
. It's more reliable.
– eryksun
Nov 23 at 1:22
Assuming thatSERVICE_STATUS_HANDLE
is an opaque pointer type, you must setadvapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g.c_void_p
), then you must either manually wrap the result as a pointer instance (e.g.result = c_void_p(result)
) to get around the automatic integer conversion, or else setargtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.
– eryksun
Nov 23 at 1:25
Also, it's pointless to setg_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assigng_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declareglobal g_hServiceStatus
at module scope; they're the same scope.
– eryksun
Nov 23 at 1:31
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias forctypes.c_void_p
. This is a simple pointer type, so when it's set as a function'srestype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type inargtypes
, the default conversion is to a 32-bitc_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't setrestype
at all, the result type also defaults to 32-bitc_int
.
– eryksun
Nov 23 at 3:19
|
show 5 more comments
Original issue is now resolved, many thanks to eryksun.
Fixed code is below, I now have a different issue that I will ask about in another thread if I cannot figure it out.
Error 6 is invalid handle, however, the handle appears to be good, I believe the error is coming from the second parameter.
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
Note: if I make the pointer None, then it doesn't fail (but obviously doesn't do anything useful either).
python -V
Python 3.6.6
Larger snippet:
from ctypes import *
from ctypes.wintypes import *
winKernel = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
global g_ServiceName
g_ServiceName = "StatusMonitor"
global g_lpcstrServiceName
g_lpcstrServiceName = LPCSTR(b"StatusMonitor")
class _SERVICE_STATUS(Structure):
_pack_ = 4
_fields_ = [
("dwServiceType", DWORD),
("dwCurrentState", DWORD),
("dwControlsAccepted", DWORD),
("dwWin32ExitCode", DWORD),
("dwServiceSpecificExitCode", DWORD),
("dwCheckPoint", DWORD),
("dwWaitHint", DWORD)
]
LPSERVICE_STATUS = POINTER(_SERVICE_STATUS)
global m_oServiceStatus
m_oServiceStatus = _SERVICE_STATUS(0, 0, 0, 0, 0, 0, 0)
global g_hServiceStatus
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
<lots of code snipped>
def status_report(dwCurrentState, dwWin32ExitCode, dwWaitHint):
global g_dwCheckPoint
global g_isService
try:
# Fill in the SERVICE_STATUS structure.
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
m_oServiceStatus.dwCurrentState = dwCurrentState
m_oServiceStatus.dwWin32ExitCode = dwWin32ExitCode
m_oServiceStatus.dwWaitHint = dwWaitHint
if dwCurrentState == SERVICE_START_PENDING:
m_oServiceStatus.dwControlsAccepted = 0
else:
m_oServiceStatus.dwControlsAccepted = 1
if (dwCurrentState == SERVICE_STOPPED) or (dwCurrentState == SERVICE_RUNNING):
m_oServiceStatus.dwCheckPoint = 0
else:
g_dwCheckPoint += 1
m_oServiceStatus.dwCheckPoint = g_dwCheckPoint
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
#logging.info("SetServiceStatus(" + str(g_hServiceStatus) + ", status=" + str(dwStatus) + ")")
logging.info("status_report(" + str(g_hServiceStatus) + ", " + str(dwCurrentState) + ", " + str(dwWin32ExitCode) + ", " + str(dwWaitHint) + ")")
dwStatus = None
if g_isService:
# Report the status of the service to the SCM.
ptrServiceStatus = LPSERVICE_STATUS(m_oServiceStatus)
logging.info("m_oServiceStatus struct: " + str(m_oServiceStatus) + ", ref: " + str(byref(m_oServiceStatus)))
logging.info(" " + "ptr: " + str(str(pointer(m_oServiceStatus))) + " PTR: " + str(ptrServiceStatus))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
if 0 == status:
dwStatus = ctypes.get_last_error()
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
logging.error("status_report " + str(e) + " line: " + str(exc_tb.tb_lineno))
return dwStatus
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
logging.info("control handler " + str(g_hServiceStatus))
logging.info("control handler called count " + str(g_nServiceControlHandlerCalled))
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_oServiceStatus.dwServiceSpecificExitCode = 0;
# set the service state as pending
dwStatus = status_report(SERVICE_START_PENDING, NO_ERROR, 3000);
logging.info("service_main: status_report(" + str(g_hServiceStatus) + "), status=" + str(dwStatus))
log_service_status(m_oServiceStatus)
Updated logging result:
INFO service_start
INFO service_start: StopEventHandle 952
INFO service_main called JimsStatusMonitor control handler called count 0
INFO control handler 2787686645712
INFO control handler called count 0
INFO status_report(2787686645712, 2, 0, 3000)128
INFO m_oServiceStatus struct: <__main__._SERVICE_STATUS object at 0x000002890FC666C8>, ref: <cparam 'P' (000002890FCA8A30)>
INFO ptr: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66848> PTR: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66648>
INFO service_main: status_report(2787686645712), status=None
INFO 16, 2, 0, 0, 0, 1, 3000
I must be missing something obvious, but I don't see it. I tried different pack to the structure, but with no improvement.
I also tried using byref() instead of pointer() and just passing the structure, but none of those worked. I believe using pointer() is correct here because there is another API to set the dispatch table that is working using pointer().
Note that I am specifically using FFI for this as I found the existing packages lacking for what I am trying to do. This Python solution is based on a C++ solution that I wrote that works, I just need to understand whatever nuance to the FFI that is causing it to fail.
I should add that the service is actually running at this point, I just can't transition it out of Starting state with this issue.
Hopefully someone can tell me what I am doing wrong?
Thanks in advance,
-Dave
python windows service ffi
Original issue is now resolved, many thanks to eryksun.
Fixed code is below, I now have a different issue that I will ask about in another thread if I cannot figure it out.
Error 6 is invalid handle, however, the handle appears to be good, I believe the error is coming from the second parameter.
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
Note: if I make the pointer None, then it doesn't fail (but obviously doesn't do anything useful either).
python -V
Python 3.6.6
Larger snippet:
from ctypes import *
from ctypes.wintypes import *
winKernel = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
global g_ServiceName
g_ServiceName = "StatusMonitor"
global g_lpcstrServiceName
g_lpcstrServiceName = LPCSTR(b"StatusMonitor")
class _SERVICE_STATUS(Structure):
_pack_ = 4
_fields_ = [
("dwServiceType", DWORD),
("dwCurrentState", DWORD),
("dwControlsAccepted", DWORD),
("dwWin32ExitCode", DWORD),
("dwServiceSpecificExitCode", DWORD),
("dwCheckPoint", DWORD),
("dwWaitHint", DWORD)
]
LPSERVICE_STATUS = POINTER(_SERVICE_STATUS)
global m_oServiceStatus
m_oServiceStatus = _SERVICE_STATUS(0, 0, 0, 0, 0, 0, 0)
global g_hServiceStatus
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
<lots of code snipped>
def status_report(dwCurrentState, dwWin32ExitCode, dwWaitHint):
global g_dwCheckPoint
global g_isService
try:
# Fill in the SERVICE_STATUS structure.
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
m_oServiceStatus.dwCurrentState = dwCurrentState
m_oServiceStatus.dwWin32ExitCode = dwWin32ExitCode
m_oServiceStatus.dwWaitHint = dwWaitHint
if dwCurrentState == SERVICE_START_PENDING:
m_oServiceStatus.dwControlsAccepted = 0
else:
m_oServiceStatus.dwControlsAccepted = 1
if (dwCurrentState == SERVICE_STOPPED) or (dwCurrentState == SERVICE_RUNNING):
m_oServiceStatus.dwCheckPoint = 0
else:
g_dwCheckPoint += 1
m_oServiceStatus.dwCheckPoint = g_dwCheckPoint
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
#logging.info("SetServiceStatus(" + str(g_hServiceStatus) + ", status=" + str(dwStatus) + ")")
logging.info("status_report(" + str(g_hServiceStatus) + ", " + str(dwCurrentState) + ", " + str(dwWin32ExitCode) + ", " + str(dwWaitHint) + ")")
dwStatus = None
if g_isService:
# Report the status of the service to the SCM.
ptrServiceStatus = LPSERVICE_STATUS(m_oServiceStatus)
logging.info("m_oServiceStatus struct: " + str(m_oServiceStatus) + ", ref: " + str(byref(m_oServiceStatus)))
logging.info(" " + "ptr: " + str(str(pointer(m_oServiceStatus))) + " PTR: " + str(ptrServiceStatus))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
if 0 == status:
dwStatus = ctypes.get_last_error()
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
logging.error("status_report " + str(e) + " line: " + str(exc_tb.tb_lineno))
return dwStatus
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
logging.info("control handler " + str(g_hServiceStatus))
logging.info("control handler called count " + str(g_nServiceControlHandlerCalled))
m_oServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_oServiceStatus.dwServiceSpecificExitCode = 0;
# set the service state as pending
dwStatus = status_report(SERVICE_START_PENDING, NO_ERROR, 3000);
logging.info("service_main: status_report(" + str(g_hServiceStatus) + "), status=" + str(dwStatus))
log_service_status(m_oServiceStatus)
Updated logging result:
INFO service_start
INFO service_start: StopEventHandle 952
INFO service_main called JimsStatusMonitor control handler called count 0
INFO control handler 2787686645712
INFO control handler called count 0
INFO status_report(2787686645712, 2, 0, 3000)128
INFO m_oServiceStatus struct: <__main__._SERVICE_STATUS object at 0x000002890FC666C8>, ref: <cparam 'P' (000002890FCA8A30)>
INFO ptr: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66848> PTR: <__main__.LP__SERVICE_STATUS object at 0x000002890FC66648>
INFO service_main: status_report(2787686645712), status=None
INFO 16, 2, 0, 0, 0, 1, 3000
I must be missing something obvious, but I don't see it. I tried different pack to the structure, but with no improvement.
I also tried using byref() instead of pointer() and just passing the structure, but none of those worked. I believe using pointer() is correct here because there is another API to set the dispatch table that is working using pointer().
Note that I am specifically using FFI for this as I found the existing packages lacking for what I am trying to do. This Python solution is based on a C++ solution that I wrote that works, I just need to understand whatever nuance to the FFI that is causing it to fail.
I should add that the service is actually running at this point, I just can't transition it out of Starting state with this issue.
Hopefully someone can tell me what I am doing wrong?
Thanks in advance,
-Dave
python windows service ffi
python windows service ffi
edited Nov 23 at 7:03
asked Nov 22 at 19:23
crusty-dave
113
113
Useadvapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
andctypes.get_last_error()
instead ofGetLastError()
. It's more reliable.
– eryksun
Nov 23 at 1:22
Assuming thatSERVICE_STATUS_HANDLE
is an opaque pointer type, you must setadvapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g.c_void_p
), then you must either manually wrap the result as a pointer instance (e.g.result = c_void_p(result)
) to get around the automatic integer conversion, or else setargtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.
– eryksun
Nov 23 at 1:25
Also, it's pointless to setg_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assigng_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declareglobal g_hServiceStatus
at module scope; they're the same scope.
– eryksun
Nov 23 at 1:31
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias forctypes.c_void_p
. This is a simple pointer type, so when it's set as a function'srestype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type inargtypes
, the default conversion is to a 32-bitc_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't setrestype
at all, the result type also defaults to 32-bitc_int
.
– eryksun
Nov 23 at 3:19
|
show 5 more comments
Useadvapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
andctypes.get_last_error()
instead ofGetLastError()
. It's more reliable.
– eryksun
Nov 23 at 1:22
Assuming thatSERVICE_STATUS_HANDLE
is an opaque pointer type, you must setadvapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g.c_void_p
), then you must either manually wrap the result as a pointer instance (e.g.result = c_void_p(result)
) to get around the automatic integer conversion, or else setargtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.
– eryksun
Nov 23 at 1:25
Also, it's pointless to setg_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assigng_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declareglobal g_hServiceStatus
at module scope; they're the same scope.
– eryksun
Nov 23 at 1:31
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias forctypes.c_void_p
. This is a simple pointer type, so when it's set as a function'srestype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type inargtypes
, the default conversion is to a 32-bitc_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't setrestype
at all, the result type also defaults to 32-bitc_int
.
– eryksun
Nov 23 at 3:19
Use
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
and ctypes.get_last_error()
instead of GetLastError()
. It's more reliable.– eryksun
Nov 23 at 1:22
Use
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
and ctypes.get_last_error()
instead of GetLastError()
. It's more reliable.– eryksun
Nov 23 at 1:22
Assuming that
SERVICE_STATUS_HANDLE
is an opaque pointer type, you must set advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g. c_void_p
), then you must either manually wrap the result as a pointer instance (e.g. result = c_void_p(result)
) to get around the automatic integer conversion, or else set argtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.– eryksun
Nov 23 at 1:25
Assuming that
SERVICE_STATUS_HANDLE
is an opaque pointer type, you must set advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g. c_void_p
), then you must either manually wrap the result as a pointer instance (e.g. result = c_void_p(result)
) to get around the automatic integer conversion, or else set argtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.– eryksun
Nov 23 at 1:25
Also, it's pointless to set
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assign g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declare global g_hServiceStatus
at module scope; they're the same scope.– eryksun
Nov 23 at 1:31
Also, it's pointless to set
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assign g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declare global g_hServiceStatus
at module scope; they're the same scope.– eryksun
Nov 23 at 1:31
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias for ctypes.c_void_p
. This is a simple pointer type, so when it's set as a function's restype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type in argtypes
, the default conversion is to a 32-bit c_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't set restype
at all, the result type also defaults to 32-bit c_int
.– eryksun
Nov 23 at 3:19
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias for ctypes.c_void_p
. This is a simple pointer type, so when it's set as a function's restype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type in argtypes
, the default conversion is to a 32-bit c_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't set restype
at all, the result type also defaults to 32-bit c_int
.– eryksun
Nov 23 at 3:19
|
show 5 more comments
1 Answer
1
active
oldest
votes
With many thanks to eryksun, I was able to resolve the original issue.
The main issue was that I was assuming the Windows APIs were fully defined because it seemed like they were working without restype and argstype defined.
Needed the following:
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
With those defined correctly, there were still two remaining issues that I was able to figure out from the documentation.
The first was I missed that restype is the first argument to WINFUNCTYPE(), given the responses from eryksun, it was more obvious to me, and that explained why my definition for my service_main() wasn't working as expected.
The second was a bit more subtle and is found at the end of the callback documentation here:
Important note for callback functions:
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn't, and if you don't, they may be
garbage collected, crashing your program when a callback is made.
Note that the original code that was failing can be found in the Python forum here.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437028%2fpython-advapi32-setservicestatus-fails-with-error-6%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
With many thanks to eryksun, I was able to resolve the original issue.
The main issue was that I was assuming the Windows APIs were fully defined because it seemed like they were working without restype and argstype defined.
Needed the following:
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
With those defined correctly, there were still two remaining issues that I was able to figure out from the documentation.
The first was I missed that restype is the first argument to WINFUNCTYPE(), given the responses from eryksun, it was more obvious to me, and that explained why my definition for my service_main() wasn't working as expected.
The second was a bit more subtle and is found at the end of the callback documentation here:
Important note for callback functions:
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn't, and if you don't, they may be
garbage collected, crashing your program when a callback is made.
Note that the original code that was failing can be found in the Python forum here.
add a comment |
With many thanks to eryksun, I was able to resolve the original issue.
The main issue was that I was assuming the Windows APIs were fully defined because it seemed like they were working without restype and argstype defined.
Needed the following:
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
With those defined correctly, there were still two remaining issues that I was able to figure out from the documentation.
The first was I missed that restype is the first argument to WINFUNCTYPE(), given the responses from eryksun, it was more obvious to me, and that explained why my definition for my service_main() wasn't working as expected.
The second was a bit more subtle and is found at the end of the callback documentation here:
Important note for callback functions:
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn't, and if you don't, they may be
garbage collected, crashing your program when a callback is made.
Note that the original code that was failing can be found in the Python forum here.
add a comment |
With many thanks to eryksun, I was able to resolve the original issue.
The main issue was that I was assuming the Windows APIs were fully defined because it seemed like they were working without restype and argstype defined.
Needed the following:
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
With those defined correctly, there were still two remaining issues that I was able to figure out from the documentation.
The first was I missed that restype is the first argument to WINFUNCTYPE(), given the responses from eryksun, it was more obvious to me, and that explained why my definition for my service_main() wasn't working as expected.
The second was a bit more subtle and is found at the end of the callback documentation here:
Important note for callback functions:
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn't, and if you don't, they may be
garbage collected, crashing your program when a callback is made.
Note that the original code that was failing can be found in the Python forum here.
With many thanks to eryksun, I was able to resolve the original issue.
The main issue was that I was assuming the Windows APIs were fully defined because it seemed like they were working without restype and argstype defined.
Needed the following:
advapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
advapi32.RegisterServiceCtrlHandlerExA.argtypes = [LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID]
g_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(g_lpcstrServiceName, LPHANDLER_FUNCTION_EX(svc_control_handler_ex), LPVOID(None))
advapi32.SetServiceStatus.restype = BOOL
advapi32.SetServiceStatus.argtypes = [SERVICE_STATUS_HANDLE, LPSERVICE_STATUS]
status = advapi32.SetServiceStatus(g_hServiceStatus, ptrServiceStatus)
With those defined correctly, there were still two remaining issues that I was able to figure out from the documentation.
The first was I missed that restype is the first argument to WINFUNCTYPE(), given the responses from eryksun, it was more obvious to me, and that explained why my definition for my service_main() wasn't working as expected.
The second was a bit more subtle and is found at the end of the callback documentation here:
Important note for callback functions:
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn't, and if you don't, they may be
garbage collected, crashing your program when a callback is made.
Note that the original code that was failing can be found in the Python forum here.
answered Nov 23 at 5:46
crusty-dave
113
113
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437028%2fpython-advapi32-setservicestatus-fails-with-error-6%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Use
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
andctypes.get_last_error()
instead ofGetLastError()
. It's more reliable.– eryksun
Nov 23 at 1:22
Assuming that
SERVICE_STATUS_HANDLE
is an opaque pointer type, you must setadvapi32.RegisterServiceCtrlHandlerExA.restype = SERVICE_STATUS_HANDLE
. If it's a simple ctypes pointer (e.g.c_void_p
), then you must either manually wrap the result as a pointer instance (e.g.result = c_void_p(result)
) to get around the automatic integer conversion, or else setargtypes
for all functions that use the pointer. That said, you should be setting the full prototype for all FFI functions anyway. Type safety is extremely important with ctypes code.– eryksun
Nov 23 at 1:25
Also, it's pointless to set
g_hServiceStatus = SERVICE_STATUS_HANDLE(None)
and subsequently assigng_hServiceStatus = advapi32.RegisterServiceCtrlHandlerExA(...)
in the same scope. It's also redundant to declareglobal g_hServiceStatus
at module scope; they're the same scope.– eryksun
Nov 23 at 1:31
SERVICE_STATUS_HANDLE is defined in wintypes.py, so I wouldn't have thought I would need to do anything different with that? I have only defined the things that are not defined there. I am trying some of your suggestions, will update...
– crusty-dave
Nov 23 at 2:26
ctypes.wintypes.SERVICE_STATUS_HANDLE
is an alias forctypes.c_void_p
. This is a simple pointer type, so when it's set as a function'srestype
, the return value is automatically converted to a Python integer. If you pass this integer to a function without setting the type inargtypes
, the default conversion is to a 32-bitc_int
, which will truncate the upper 32-bit part of the pointer value if you're using 64-bit Python. Similarly, if you don't setrestype
at all, the result type also defaults to 32-bitc_int
.– eryksun
Nov 23 at 3:19