Python:advapi32.SetServiceStatus()失败,错误6

时间:2018-11-22 19:23:01

标签: python windows service ffi

原来的问题现在已经解决,这要归功于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失败的FFI的细微差别。

我应该补充一点,此服务实际上正在运行,因此我无法将其从“开始”状态过渡到该状态。

希望有人能告诉我我做错了吗?

预先感谢, -戴夫

1 个答案:

答案 0 :(得分:1)

非常感谢eryksun,我得以解决原始问题。

主要问题是我假设Windows API已完全定义,因为它们似乎在未定义restype和argstype的情况下工作。

需要以下内容:

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)

在正确定义了这些问题之后,我仍然可以从文档中找出另外两个问题。

首先,我错过了restype是WINFUNCTYPE()的第一个参数,考虑到eryksun的响应,这对我来说更明显,并且这解释了为什么我对service_main()的定义无法按预期工作。

第二个稍微有些微妙,可以在回调文档here的末尾找到:

  

回调函数的重要说明:

     

确保只要您一直引用CFUNCTYPE对象   从C代码使用。 ctypes不会,如果您不这样做,它们可能是   垃圾回收,在进行回调时会使程序崩溃。

请注意,失败的原始代码可以在Python论坛here中找到。