Windows 服务工作正常,字符集为 unicode,但多字节的相同代码开始失败,出现 1053 错误

Windows Service is working fine with character set as unicode but same code with multi-byte is start to failed with 1053 error

基本 windows 带有发布配置 + unicode 字符集的 c++ 服务示例代码在管理控制台中使用 sc start cmd 完美地开始,但是当我更改配置 release+ 多字节而不是 sc start cmd 失败时最常见的服务错误:1053 - 服务没有及时响应启动或控制请求。

我不知道这个 unicode 与多字节配置之间的关系是什么。即使我已经交叉检查每个函数后缀,这是预期的,就像在 unicode 模式下后缀是 W 而在多字节模式下后缀是 A


#define SERVICE_NAME    "USB Device Monitor Service"
#define SLEEP_TIME  (1000)

void main()
{
    SERVICE_TABLE_ENTRY ServiceTable[1];
    ServiceTable[0].lpServiceName = SERVICE_NAME;
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

    StartServiceCtrlDispatcher(ServiceTable);
}

void ServiceMain()
{
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    Status.dwCurrentState = SERVICE_START_PENDING;
    Status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    Status.dwWin32ExitCode = 0;
    Status.dwServiceSpecificExitCode = 0;
    Status.dwCheckPoint = 0;
    Status.dwWaitHint = 0;

    hStatus = RegisterServiceCtrlHandlerEx(SERVICE_NAME, (LPHANDLER_FUNCTION_EX)ControlHandler, 0);

    if ((SERVICE_STATUS_HANDLE)0 == hStatus)
    {
        // Error
    }
    SetServiceStatus(hStatus, &Status);

    Status.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &Status);

    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

    // Initialization
    hDeviceNotify = RegisterDeviceNotification((HANDLE)hStatus, &NotificationFilter, DEVICE_NOTIFY_SERVICE_HANDLE);

    if (NULL == hDeviceNotify)
    {
        // Error
    }

    while (SERVICE_RUNNING == Status.dwCurrentState)
    {
        Sleep(SLEEP_TIME);
    }
}

DWORD ControlHandler(DWORD dwControl, DWORD dwEventType,
    LPVOID lParam, LPVOID lpContext)
{
    switch (dwControl)
    {
    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
        UnregisterDeviceNotification(hDeviceNotify);
        Status.dwCurrentState = SERVICE_STOPPED;
        SetServiceStatus(hStatus, &Status);
        CloseHandle(hPipe);
        return NO_ERROR;

    case SERVICE_CONTROL_DEVICEEVENT:
        if ((DBT_DEVICEARRIVAL == dwEventType) || (DBT_DEVICEREMOVECOMPLETE == dwEventType))
        {
            try
            {
                DEV_BROADCAST_HDR* header = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
                if (DBT_DEVTYP_DEVICEINTERFACE == header->dbch_devicetype)
                {
                    //parse intrested USB device only
                }
            }
            catch (const std::nullptr_t /*ex*/)
            {
                //"ERROR: Processing WM_DEVICECHANGE failed
            }
        }
        break;
    default:
        //"ERROR : Unknown dwControl: dwControl)
        SetServiceStatus(hStatus, &Status);
        break;
    }

    return NO_ERROR;
}

您的 ServiceMain()ControlHandler() 函数声明错误,但您使用 type-casts 来阻止编译器报错。任何时候你不得不求助于使用 type-cast 来让编译器安静下来,想想你的代码试图做什么,因为它可能做错了什么。

此外,您传递给 StartServiceCtrlDispatcher()SERVICE_TABLE_ENTRY[] 数组不完整 - 您不是 NULL-terminating 数组,就像文档中说的那样。

就此而言,您声称您的服务在为 Unicode 编译时有效,但您显示的代码实际上不会在 Unicode 下编译,因为 ServiceTable[0].lpServiceName 字段需要一个 Unicode 字符串,但显示的代码正在分配一个 ANSI 字符串,这是一个错误。

我建议你阅读微软的文档,并密切注意它给出的例子:

Service Program Tasks

The following tasks are performed by service programs:

Related Topics

The Complete Service Sample

话虽如此,试试这样的东西:

#define SERVICE_NAME    TEXT("USB Device Monitor Service")

HANDLE hStopEvent = NULL;
SERVICE_STATUS_HANDLE hStatus = NULL;

SERVICE_STATUS Status;

DWORD WINAPI ControlHandler(DWORD dwControl, DWORD dwEventType,
    LPVOID lParam, LPVOID lpContext)
{
    switch (dwControl)
    {
        case SERVICE_CONTROL_INTERROGATE:
            return NO_ERROR;

        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
            SetEvent(hStopEvent);
            return NO_ERROR;

        case SERVICE_CONTROL_DEVICEEVENT:
            if ((DBT_DEVICEARRIVAL == dwEventType) || (DBT_DEVICEREMOVECOMPLETE == dwEventType))
            {
                try
                {
                    DEV_BROADCAST_HDR* header = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
                    if (DBT_DEVTYP_DEVICEINTERFACE == header->dbch_devicetype)
                    {
                        //parse intrested USB device only
                    }
                }
                catch (const std::nullptr_t /*ex*/)
                {
                    //"ERROR: Processing WM_DEVICECHANGE failed
                }
            }
            break;

        default:
            //"ERROR : Unknown dwControl: dwControl)
            break;
    }

    return NO_ERROR;
}

void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
    hStatus = RegisterServiceCtrlHandlerEx(SERVICE_NAME, &ControlHandler, 0);
    if (!hStatus)
    {
        // Error
        return;
    }

    ZeroMemory(&Status, sizeof(Status));
    Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    Status.dwCurrentState = SERVICE_START_PENDING;
    SetServiceStatus(hStatus, &Status);

    // Initialization

    hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!hStopEvent)
    {
        // Error
        Status.dwCurrentState = SERVICE_STOPPED;
        Status.dwWin32ExitCode = GetLastError();
        SetServiceStatus(hStatus, &Status);
        return;
    }

    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;

    HDEVNOTIFY hDeviceNotify = RegisterDeviceNotification((HANDLE)hStatus, &NotificationFilter, DEVICE_NOTIFY_SERVICE_HANDLE);
    if (!hDeviceNotify)
    {
        // Error
        Status.dwCurrentState = SERVICE_STOPPED;
        Status.dwWin32ExitCode = GetLastError();
        SetServiceStatus(hStatus, &Status);
        return;
    }

    Status.dwCurrentState = SERVICE_RUNNING;
    Status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    SetServiceStatus(hStatus, &Status);

    WaitForSingleObject(hStopEvent, INFINITE);

    Status.dwCurrentState = SERVICE_STOP_PENDING;
    Status.dwControlsAccepted = 0;
    SetServiceStatus(hStatus, &Status);

    UnregisterDeviceNotification(hDeviceNotify);
    CloseHandle(hStopEvent);

    Status.dwCurrentState = SERVICE_STOPPED;
    SetServiceStatus(hStatus, &Status);
}

int main()
{
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = SERVICE_NAME;
    ServiceTable[0].lpServiceProc = &ServiceMain;
    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;

    StartServiceCtrlDispatcher(ServiceTable);

    return 0;
}