Search code examples
unicodewindows-services

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


The basic windows service example code in c++ with release configuration + unicode character set is perfectly start using sc start cmd in admin console but when i change the configuration release+ multi-byte than sc start cmd fail with most common service error : 1053 -The service did not respond to the start or control request in a timely fashion.

I don't know what is the relation between this unicode vs multi-byte config. even i have cross-check each function suffix and that is expected like in unicode mode suffix is W and in multi-byte mode suffix is 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;
}

Solution

  • Your ServiceMain() and ControlHandler() functions are declared wrong, but you are using type-casts to stop the compiler from complaining. Any time you have to resort to using a type-cast to quiet the compiler, think about what your code is trying to do, as it is likely doing something wrong.

    Also, the SERVICE_TABLE_ENTRY[] array that you are passing to StartServiceCtrlDispatcher() is incomplete - you are not NULL-terminating the array, like the documentation says to do.

    For that matter, you claim that your service works when compiling for Unicode, but the code you have shown won't actually compile under Unicode, because the ServiceTable[0].lpServiceName field will be expecting a Unicode string but the code shown is assigning an ANSI string instead, which is an error.

    I suggest you read Microsoft's documentation, and pay close attention to the examples it gives:

    Service Program Tasks

    The following tasks are performed by service programs:

    Related Topics

    The Complete Service Sample

    With that said, try something more like this:

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