0

I am writing a service based on the tutorial at the following page: https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus

I can successfully create the service using:

sc create service_name binPath=<path_name>

When I attempt to start the service, I get the following error:

sc start service_name
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.

Here is my main():

int main (int argc, char *argv[])
{
    OutputDebugString("service_name: entered main");
    SERVICE_TABLE_ENTRY ServiceTable[] = 
    {
        {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
        {NULL, NULL}
    };

    if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
    {
        return GetLastError();
    }

    return 0;
}

EDIT: I switched from log files to OutputDebugString()/DebugView

I ran DebugView, and I never receive "entered main". However, if I replace the contents of my worker thread with a return statement, I do start up successfully, and I receive the debug message, so I know that DebugView is working correctly.

Here is where I create my worker thread:

// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
if (hThread) {
    // Wait until our worker thread exits, so we can set state to SERVICE_STOPPED and return needs to stop
    WaitForSingleObject (hThread, INFINITE);
} else {
    OutputDebugString("service_name: ServiceMain: CreateThread returned NULL");
}

It seems like my worker thread is responsible for the startup error, but why wouldn't I get debug messages at the top of main()?

  • What's the outFilePath? Is it possible the service account doesn't have permission to write to it, so your service is crashing? – user253751 Aug 08 '18 at 00:49
  • Is your project set to unicode or multibyte? You'll most likely be much happier if you are explicit about your types and avoid anything `TCHAR` related unless you know exactly how it works and are sure you need it. – Retired Ninja Aug 08 '18 at 00:50
  • Are you building in Debug or Release? See [this question](https://stackoverflow.com/questions/158371/error-1053-the-service-did-not-respond-to-the-start-or-control-request-in-a-tim). – 1201ProgramAlarm Aug 08 '18 at 01:28
  • You never check for errors opening the file. If you want a more reliable way for a piece of software to report its progress, call [OutputDebugString](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) instead. That output will appear in your debugger's Output window. If you aren't running the code under a debugger, you can use tools like [DebugView](https://learn.microsoft.com/en-us/sysinternals/downloads/debugview) to receive the output. – IInspectable Aug 08 '18 at 08:09
  • @immibis I replaced the contents of my worker thread with a return statement, and then the startup is successful, and the file does get written, so I know that I have permission, am looking in the correct directory, etc. – SloppyNick Aug 08 '18 at 15:35
  • @1201ProgramAlarm I'm in Release. – SloppyNick Aug 08 '18 at 15:36
  • Why do you wait for worker thread to exit after creating it? This will lock your service dispatcher thread. As to "signaling that the service needs to stop", it's the other way round - a service dispatcher callback tell you to stop your worker thread. –  Aug 08 '18 at 16:31
  • @Arkadiy I'm following the tutorial that I posted at the top of the post. Every example I've seen follows this pattern of waiting at the end of ServiceMain. However, I do realize that the comment is misleading, so I've edited it. – SloppyNick Aug 08 '18 at 17:55

2 Answers2

0

If your service was created successfully, you should see it in the list of Windows Services ( Computer Management -> Services and Applications->Services). If it is not present, then it was not registered properly. If it is present, you could try to start it from Windows Service console. Your's _tmain is just not called by the service, no log will be produced.

Valeca
  • 122
  • 8
  • There is no problem with service creation. The problem lies in service startup (note the error message I described). I know that my main() isn't getting called. My question is: why not? – SloppyNick Aug 09 '18 at 16:54
  • @SloppyNick Did you provide the full path to the service binary location including its name? If not, then this is the reason it doesn't find the file. – Valeca Aug 09 '18 at 20:47
  • f you did, then the service might not running under appropriate account permissions. Have a look at this one https://support.microsoft.com/en-ca/help/886695/you-receive-an-error-1053-the-service-did-not-respond-to-the-start-or If you log in your system with admin rights, this shouldn't be the case though. – Valeca Aug 09 '18 at 20:59
  • I can successfully create the service, so the SCM can find the file. The problem is starting the service. I am starting it via a console running as admin. – SloppyNick Aug 09 '18 at 22:10
0

You need to update the SCM states using SetServiceStatus function.

If initializing your service takes a long time, you should update the state periodically with the SERVICE_START_PENDING state.

When the initialization is finished, you must update the SCM state to SERVICE_RUNNING.

Other states are:

-SERVICE_STOP_PENDING.

-SERVICE_PAUSE_PENDING.

-SERVICE_CONTINUE_PENDING.

-SERVICE_STOPPED.

My function that sends the state to the SCM is as follows:

BOOL SendStatusToSCM
                    (
                    DWORD dwCurrentState,
                    DWORD dwWin32ExitCode, 
                    DWORD dwServiceSpecificExitCode,
                    DWORD dwCheckPoint,
                    DWORD dwWaitHint
                    )
{
BOOL success;
SERVICE_STATUS serviceStatus;

// Preenche os campos do service status

serviceStatus.dwServiceType     = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState    = dwCurrentState;

if (dwCurrentState == SERVICE_START_PENDING)
    serviceStatus.dwControlsAccepted = 0;
else
    serviceStatus.dwControlsAccepted = 
        SERVICE_ACCEPT_STOP |
        SERVICE_ACCEPT_PAUSE_CONTINUE |
        SERVICE_ACCEPT_SHUTDOWN;

if (dwServiceSpecificExitCode == 0)
    serviceStatus.dwWin32ExitCode =
        dwWin32ExitCode;
else
    serviceStatus.dwWin32ExitCode = 
        ERROR_SERVICE_SPECIFIC_ERROR;
serviceStatus.dwServiceSpecificExitCode =
    dwServiceSpecificExitCode;

serviceStatus.dwCheckPoint = dwCheckPoint;
serviceStatus.dwWaitHint = dwWaitHint;

// Passa o status para o SCM

success = SetServiceStatus
                            (
                            serviceStatusHandle,
                            &serviceStatus
                            );
if (!success)
    exit( 99 );

return success;
}

With this create below the start service works perfectly and always activates the main():

serv=CreateService (

sc,

noServ,                     //  service name

noDisp,                     //  display name

SERVICE_ALL_ACCESS,         //  desired access

SERVICE_WIN32_OWN_PROCESS,  //  service type

SERVICE_AUTO_START,         //  modo de iniciar o serviço

SERVICE_ERROR_NORMAL,       //  gravidade da falha do serviço

noExec,                     //  nome do executável

NULL,                       //  nome do grupo ao qual pertence

NULL,                       //  tag id

NULL,                       //  tabela de dependências

NULL,                       //  account name 

NULL                        //  account password

);
  • I am updating my state to the SCM. I haven't posted the entirety of my code, but it closely follows the tutorial I mentioned in the OP. – SloppyNick Aug 09 '18 at 16:44
  • I edited my answer and put the form I use to create the service. Especially the service type can be sensitive to start it. Are you sure the main is not being called? – Sergio J. Batarce Aug 11 '18 at 15:38