Link to home
Start Free TrialLog in
Avatar of dmetzler
dmetzler

asked on

NT service

I have created an NT service/app hybrid.  When starting up the service, I get a timeout error (running in Win2000 Pro):

Microsoft Management Console gives an error of:

Error 1053: The service did not respond to the start or control request in a timely fashion.

What does this mean, specifically, and where do I look in my code to correct it?

I also get a system log error: Timeout (30000 milliseconds) waiting for service to connect.  (Before the above error).  However, it is not 30 seconds but close to 5 seconds.

Thanks,

Don
Avatar of leflon
leflon
Flag of Germany image

is your service running so you get the error?
i had a service which did a lot of initializing, so the service control manager states a timeout error. but when i checked the running services "net start" th e service was runnig ok.
after i moved the init code the service starts ok.
maybe u got the same problem.
your app ids starting ok?
Avatar of dmetzler
dmetzler

ASKER

No - the service does not get to run - it stops with an error.  It looks like the SERVICE_ALL_ACCESS changes this so it will run, but then it exits almost immediately.

How do I keep my service running until it gets a stop request?

Thanks!

Don
What code are you using in your 'ServiceMain()' function? Are you reporting 'SERVICE_RUNNING' to the SCM correctly?

>>
What code are you using in your 'ServiceMain()' function? Are you reporting 'SERVICE_RUNNING' to the SCM correctly?
>>

I think so, but I will check.

Also - does the ServiceMain() function run in a new thread?  If so, how can I call methods in the main CWinApp derived application?

Thanks!

Son

>> 
What code are you using in your 'ServiceMain()' function? Are you reporting 'SERVICE_RUNNING' to the SCM correctly?
>> 

Yes - this is being done.  Then I sit in a loop until a flag is set to let me know to exit the service/application.  It seems I will need to handle the main app msg queue checking here - yes?

Thanks,

Don (not Son)

Hmm - could you post the code?

Essentially, it looks like this (some things are missing, but I have included the ServiceMain routine from the CASService class):

void CMyApp::InitInstance()
{
   if (bService)
   {
       StartNTService();
   }
}

void CMyApp::StartNTService()
{
   CASService  service;
}

void CASService::ServiceMain()
{
   RegisterCtrlHandler();

   m_bStopped = FALSE;

   ReportStatusToSCM(SERVICE_START_PENDING, NO_ERROR, 0, 1, 0);
   Sleep(500);
   ReportStatusToSCM(SERVICE_RUNNING, NO_ERROR, 0, 1, 0);

   // sit in a tight-loop until we're ready to exit
   while (!m_bStopped)
   {
      theApp.CheckStatus();
   }
}



Could you post the code for 'CheckStatus()' also?
It's pretty simple - it current checks memory and disk drive space - nothing complicated.

Don

Have you considered something like this (a loop seems to be a bit inappropriate to me):

void    SocketServerStartup ()
{
    HANDLE  hEvent;

    hEvent  =   CreateEvent (   NULL,   FALSE,  FALSE,  TEXT    (   OBJECT_NAME));

    if  (       ERROR_ALREADY_EXISTS    ==  GetLastError    ()
            ||  ERROR_SUCCESS           ==  GetLastError    ()
        )
        {
            HANDLE  hThread;
            DWORD   dwTID;

            hThread =   CreateThread    (   NULL,
                                            0,
                                            CommThread,
                                            NULL,
                                            0,
                                            &dwTID
                                            );

            DBGTRACE   (   L"SocketServerStartup():\twaiting for stop event...\n");

            ReportStatusToSCMgr (   SERVICE_RUNNING,
                                    g_dwErr,
                                    0
                                );


            WaitForSingleObject (   hEvent, INFINITE);

            DBGTRACE   (   L"SocketServerStartup():\treceived stop event...\n");

            return;
        }
}

void    ServiceStop (   void)
{
    HANDLE  hEvent;

    ReportStatusToSCMgr (   SERVICE_STOP_PENDING,  
                            NO_ERROR,
                            1000
                        );
    hEvent  =   CreateEvent (   NULL,   FALSE,  FALSE,  TEXT    (   OBJECT_NAME));

    if  (   ERROR_ALREADY_EXISTS    ==  GetLastError    ())
        {
            DBGTRACE   (   L"HPSUDServiceStop():\tsetting event...\n");

            SetEvent    (   hEvent);
        }

    Sleep   (   500);

    ReportStatusToSCMgr (   SERVICE_STOPPED,
                            NO_ERROR,
                            0
                        );

}

VOID WINAPI     ServiceCtrl (   DWORD   dwCtrlCode)
{
    //  Handle the requested control code.
    switch  (   dwCtrlCode)
            {
                //  stop service.
                case SERVICE_CONTROL_STOP:

                    ServiceStop ();
                    return;

                //  update the service status.
                case SERVICE_CONTROL_INTERROGATE:
                    break;

                //  invalid control code
                default:
                    break;

            }

    ReportStatusToSCMgr (   g_ssStatus.dwCurrentState,  NO_ERROR,   0);

}



Using an event seems to be a better way.  I will implement this.

However, my real concern is the call to theApp.CheckStatus().  Is this reference still valid now that my service is running in a new thread?  What happens to the original thread for the CWinApp derived class?

I understand about 90% of what is happening, but need to get over the last 10%.

Thanks!

Don
>>Is this reference still valid now that my service is running
>>in a new thread? 

It is (assuming that it is global), but if you're about to use several threads, you'll have to protect the access to it ...

>>
It is (assuming that it is global), but if you're about to use several threads, you'll have to protect the access to it ...
>>

Like with a CSingleLock?

Yes - I am doing that.

The odd thing is that after the CWinApp starts and calls the thread functions, the tray icon installed by the CWinApp disappears, as if the main app thread has exited.

Don
>>The odd thing is that after the CWinApp starts and calls
>>the thread functions, the tray icon installed by the
>>CWinApp disappears

That's not odd at all - you'll have to use a message pump to process the callback messages from the system tray icon, otherwise it'll lead the system to remove the icon...
>>
That's not odd at all - you'll have to use a message pump to process the callback messages from the system tray icon, otherwise it'll lead the system to remove the icon...
>>

I did not know that, but that you.

One other thing - my service name is the same as the display name.  Would this be a problem?


No, this usually isn't a problem (though that maybe your service name is is a bit less 'illustrating' than the display name ;-)


Okay - I have my service functions communicating with the SCM successfully.  However, now I need to get the main CWinApp thread to complete and process.  It seems when the service code starts, the main app thread is suspended.  When the service stops, then the main app continues.

Is there a good way to handle this, perhaps by having my service code start at the end of the CWinApp::InitInstance() or perhaps via callback message?

Is there anyway to have both processes/threads running concurrently, but started from the same entry point?

Thanks,

Don
Hmm, this is getting weird ;-)

So, you're mixing an MFC app with an NT service?

This IS possible, but I wouldn't recomment it (MFC performance resons...) - it'd be a good idea to separate maintaining the shell tray icon from the actual service code, e.g. by starting an application using the 'Run' registry entry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run) and have it communicate with the service ( BTW, that's the way the McAfee Scanner communicates with it's SysTray Icon). The main reson for this concept is that a service does not necessarily have access rights to the currently logged-on user's window station ('LocalSystem' _usually_ has, but not necessarily).

(Err, I wrote a service that _can_ do this, but the code isn't available even for 50k points - but I know at least 10 MS URLs where they state that this is not possible... just showing off, sorry ;-)

It'll be difficult to start both a CWinApp and a service from the same entry point, as the assumptions/expections that both SCM and MFC make/have are a bit opposite - I've never tried it...
>>
Hmm, this is getting weird ;-)
>>

I like the more obscure programming challenges.  ;-)

>>
So, you're mixing an MFC app with an NT service?
>>

Yes. What if I ignore the tray icon for the service and then start a separate thread for the service, thus allowing the main app to run appropriately?

>>
...e.g. by starting an application using the 'Run' registry entry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run) and have it communicate with the service ( BTW, that's the way the McAfee Scanner communicates with it's SysTray Icon). The main reson for this concept is that a service does not necessarily have access rights to the currently logged-on user's window station ('LocalSystem' _usually_ has, but not necessarily).
>>

Is this valid for NT too?

>>
(Err, I wrote a service that _can_ do this, but the code isn't available even for 50k points - but I know at least 10 MS URLs where they state that this is not possible... just showing off, sorry ;-)
>>

So how did you do it - can you share the basic idea?

>>
It'll be difficult to start both a CWinApp and a service from the same entry point, as the assumptions/expections that both SCM and MFC make/have are a bit opposite - I've never tried it...
>>

I am close - I start the CWinApp, which kicks off another thread to start the service (which starts another thread to handle the SCM).  Sloppy perhaps, but I think I can do it.

Thanks for ALL your help.

Don
>>Yes. What if I ignore the tray icon for the service and
>>then start a separate thread for the service, thus
>>allowing the main app to run appropriately?

Hmm, could work - i.e. one thread using a CWinApp, the other one calling 'StartServiceCtrlDispatcher()'

>>Is this valid for NT too?

Yes, definitely - I'm mainly using NT.

>>So how did you do it - can you share the basic idea?

The basic idea is to manipulate the access control lists for both the window station and the desktop ;-)



Thanks for all of your help!

Don
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for all of your help!
Thanx a lot!!!

Regarding to tha fact that you raised the points, it seems that I indeed could help you, and that's a really good feedback ;-)

BTW: I'm glad that this Q moved to the PAQ section as I didn't take enough care when posting the code - there's still a reference to the customer (oops ;-)  ...
Thanks for the help!

Don