Python: advapi32.SetServiceStatus() fails with error 6












0














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










share|improve this question
























  • 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










  • 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












  • 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
















0














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










share|improve this question
























  • 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










  • 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












  • 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














0












0








0


0





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










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 at 7:03

























asked Nov 22 at 19:23









crusty-dave

113




113












  • 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










  • 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












  • 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


















  • 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










  • 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












  • 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
















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












1 Answer
1






active

oldest

votes


















1














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.






share|improve this answer





















    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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.






    share|improve this answer


























      1














      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.






      share|improve this answer
























        1












        1








        1






        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.






        share|improve this answer












        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 23 at 5:46









        crusty-dave

        113




        113






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

            Calculate evaluation metrics using cross_val_predict sklearn

            Insert data from modal to MySQL (multiple modal on website)