Первоначальная проблема теперь решена, большое спасибо eryksun.
Ниже приведен исправленный код, теперь у меня есть другая проблема, о которой я буду спрашивать в другой ветке, если не смогу ее выяснить.
Ошибка 6 - недопустимый дескриптор, однако, дескриптор, кажется, хорош, я думаю, что ошибка исходит от второго параметра.
status = advapi32.SetServiceStatus(g_hServiceStatus, pointer(m_oServiceStatus))
if 0 == status:
dwStatus = winKernel.GetLastError()
Примечание: если я сделаю указатель None, то он не 'не удается (но, очевидно, ничего полезного тоже не делает).
python -V
Python 3.6.6
Большой фрагмент:
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)
Обновлен результат ведения журнала:
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
Я, должно быть, упускаю что-то очевидное, но я этого не вижу.Я попытался использовать pack в структуре, но без улучшений.
Я также попытался использовать byref () вместо pointer () и просто передать структуру, но ничего из этого не сработало.Я считаю, что использование pointer () здесь правильно, потому что есть другой API для установки таблицы диспетчеризации, работающий с использованием pointer ().
Обратите внимание, что я специально использую FFI для этого, так как я обнаружил, что в существующих пакетах не хватаетчто я пытаюсь сделатьЭто решение Python основано на решении C ++, которое я написал и которое работает, мне просто нужно понять любой нюанс FFI, который вызывает его сбой.
Я должен добавить, что служба фактически работает в этот момент, Я просто не могу перевести его из начального состояния с этой проблемой.
Надеюсь, кто-нибудь подскажет, что я делаю не так?
Заранее спасибо, -Dave