i know this is very much a "how long is a piece of string" type of question, however i have recently inherited a couple of applications that run as windows services, and i am having problems providing a gui (accessible from a context menu in system tray) with both of them.

before you ask, the reason why we need a gui for a windows service is in order to be able to re-configure the behaviour of the windows service(s) without resorting to stopping/re-starting.

my code works fine in debug mode, and i get the context menu come up, and everything behaves correctly etc.

when i install the service via "installutil" using a named account (i.e., not Local System Account), the service runs fine, but doesn't display the icon in the system tray (i know this is normal behaviour because i don't have the "interact with desktop" option).

here is the problem though - when i choose the "LocalSystemAccount" option, and check the "interact with desktop" option, the service takes AGES to start up for no obvious reason, and i just keep getting "Could not start the ... service on Local Computer. Error 1053: the service did not respond to the start or control request in a timely fashion".

incidentally, i increased the windows service timeout from the default 30 seconds to 2 minutes via a registry hack (see http://support.microsoft.com/kb/824344, search for TimeoutPeriod in section 3), however the service start up still times out.

my first question is - why might the "Local System Account" login takes SOOOOO MUCH LONGER than when the service logs in with the non-LocalSystemAccount, causing the windows service time-out? what's could the difference be between these two to cause such different behaviour at start up?

secondly - taking a step back, all i'm trying to achieve, is simply a windows service that provides a gui for configuration - I'd be quite happy to run using the non-Local System Account (with named user/pwd), if I could get the service to interact with the desktop (that is, have a context menu available from the system tray). is this possible, and if so how?

19 Answers
19

If you continue down the road of trying to make your service interact with the user's desktop directly, you'll lose: even under the best of circumstances (i.e. "before Vista"), this is extremely tricky.

Windows internally manages several window stations, each with their own desktop. The window station assigned to services running under a given account is completely different from the window station of the logged-on interactive user. Cross-window station access has always been frowned upon, as it's a security risk, but whereas previous Windows versions allowed some exceptions, these have been mostly eliminated in Vista and later operating systems.

The most likely reason your service is hanging on startup, is because it's trying to interact with a nonexistent desktop (or assumes Explorer is running inside the system user session, which also isn't the case), or waiting for input from an invisible desktop.

The only reliable fix for these issues is to eliminate all UI code from your service, and move it to a separate executable that runs inside the interactive user session (the executable can be started using the global Startup group, for example).

Communication between your UI code and your service can be implemented using any RPC mechanism: Named Pipes work particularly well for this purpose. If your communications needs are minimal, using application-defined Service Control Manager commands might also do the trick.

It will take some effort to achieve this separation between UI and service code: however, it's the only way to make things work reliably, and will serve you well in the future.

Publisher evidence is a little-used Code Access Security (CAS) feature: only in the unlikely event that your service actually relies on the PublisherMembershipCondition will disabling it cause issues. In all other cases, it will make the permanent or intermittent startup failures go away, by no longer requiring the runtime to do expensive certificate checks (including revocation list lookups).

To debug the startup of your service, add the following to the top of the OnStart() method of your service:

while(!System.Diagnostics.Debugger.IsAttached) Thread.Sleep(100);

This will stall the service until you manually attach the Visual Studio Debugger using Debug -> Attach to Process...

Note: In general, if you need a user to interact with your service, it is better to split the GUI components into a separate Windows application that runs when the user logs in. You then use something like named pipes or some other form of IPC to establish communication between the GUI app and your service. This is in fact the only way that this is possible in Windows Vista.

I'm shooting blind here, but I've very often found that long delays in service startups are directly or indirectly caused by network function timeouts, often when attemting to contact a domain controller when looking up account SIDs - which happens very often indirectly via GetMachineAccountSid() whether you realize it or not, since that function is called by the RPC subsystem.

Same issue here - turns out one of the DLL's referenced by my service was marked as "web" and hence marked as blocked. Either antivirus or group policy prevented the service from starting (neither the CTor nor OnStart() were even being called within 30 seconds). Unblocking the reference assemblies ( stackoverflow.com/questions/3072359/… ) fixed this. This would seem to be explained by Mark Russinovich's article.
–
StuartLCJul 27 '12 at 9:25

This answer should be much higher up, in my opinion :)
–
Daniel PerssonMay 23 '14 at 13:49

That was the issue. It would be useful if you got an appropriate message when you started the service. I only caught up when I tried double clicking on the service (it was compiled as an exe) and was prompted to install the proper version of .NET
–
Circular ReferenceJul 25 '14 at 13:23

I want to echo mdb's comments here. Don't go this path. Your service is not supposed to have a UI... "No user interaction" is like the definining feature of a service.

If you need to configure your service, write another application that edits the same configuration that the service reads on startup. But make it a distinct tool -- when you want to start the service, you start the service. When you want to configure it, you run the configuration tool.

Now, if you need realtime monitoring of the service, then that's a little trickier (and certainly something I've wished for with services). Now you're talking about having to use interprocess communications and other headaches.

Worst of all, if you need user interaction, then you have a real disconnect here, because services don't interact with the user.

In your shoes I would step back and ask why does this need to be a service? And why does it need user interaction?

These two requirements are pretty incompatible, and that should raise alarms.

Hi I found your solution very useful when I encountered the problem. I found the actual problem at support.microsoft.com/kb/307806 but I was unable to understand how your solution overcomes this.Could you please explain.
–
nishantvSep 13 '12 at 4:52

I was running into a similar problem with a Service I was writing. It worked fine then one day I started getting the timeout on Start errors. It happened in one &/or both Release and Debug depending on what was going on. I had instantiated an EventLogger from System.Diagnostics, but whatever error I was seeing must have been happening before the Logger was able to write...

If you are not aware of where to look up the EventLogs, in VS you can go to your machine under the Server Explorer. I started poking around in some of the other EventLogs besides those for my Service. Under Application - .NETRuntime I found the Error logs pertinent to the error on startup. Basically, there were some exceptions in my service's constructor (one turned out to be an exception in the EventLog instance setup - which explained why I could not see any logs in my Service EventLog). On a previous build apparently there had been other errors (which had caused me to make the changes leading to the error in the EventLog set up).

Long story short - the reason for the timeout may be due to various exceptions/errors, but using the Runtime EventLogs may just help you figure out what is going on (especially in the instances where one build works but another doesn't).

I had this problem and it drove me nuts for two days…
If your problem similar to mine:

I have settings “User settings” in my windows service, so the service can do self-maintenance, without stopping and starting the service. Well, the problem is with the “user settings”, where the config file for these settings is saved in a folder under the user-profile of the user who is running the windows service under the service-exe file version.

This folder for some reason was corrupted. I deleted the folder and service start working back again happily as usual…

I had this problem, it took about a day to fix. For me the problem was that my code skipped the "main content" and effectively ran a couple of lines then finished. And this caused the error for me. It is a C# console application which installs a Windows Service, as soon as it tried to run it with the ServiceController (sc.Run() ) then it would give this error for me.

After I fixed the code to go to the main content, it would run the intended code:

ServiceBase.Run(new ServiceHost());

Then it stopped showing up.

As lots of people have already said, the error could be anything, and the solutions people provide may or may not solve it. If they don't solve it (like the Release instead of Debug, adding generatePublisherEvidence=false into your config, etc), then chances are that the problem is with your own code.

Try and get your code to run without using sc.Run() (i.e. make the code run that sc.Run() would have executed).

I had this problem too. I made it to work by changing Log On account to Local System Account. In my project I had it setup to run as Local Service account. So when I installed it, by default it was using Local Service. I'm using .net 2.0 and VS 2005. So installing .net 1.1 SP1 wouldn't have helped.