« Transhumanism, It’s ok to see that good isn’t good enough for everyone. | Main | XmlSerializer ctor failure in ASP.NET context »

Creating Windows Services

Summary

Here’s the summary of what to remember when creating a new Windows Service. For more information on the process of discovering these tips read the details below.

1.      By default, a Windows Service project is missing an installer. From a service design view, right click select “Add Installer”.

2.      By default, the ServiceProcessInstaller component is configured to use a “User” account, change it to either “LocalService” or “LocalSystem” depending on security concerns.

3.      By default, a setup project does not invoke the custom installers contained within assemblies added to it. From the setup project’s Custom Actions Editor, right click select “Add Custom Action…” and select the primary output from the service application.

4.      When having difficulties, use the installutil tool to obtain detailed installation progress logging output.

Details

I started this note when what should have been a simple process, creating the shell for a new Windows Service project, began taking much too long.

Conceptually the goal isn’t complicated:

1.      Create an EXE containing the service implementation following the Visual Studio 2003 Windows Service project template.

2.      Create an installer for the service.

3.      Install it.

4.      Verify that it appears in the list of installed services.

The first time around I made changes to the default names of the various components as appropriate for a real project. When this didn’t work I tried again and left every name at its default value. I created a new empty solution, added a Windows Service project, opened the design view on Service1.cs, right clicked and selected “Add Installer”, added a Setup project to the solution consuming the primary output of the WindowsService1 project.

This results in the following names being assigned:

1.      WindowsService1: The name of the service project.

2.      WindowsService1.exe: The executable containing the service implementation.

3.      WindowsService1: The service project namespace.

4.      Service1: The service class.

5.      Service1: The “ServiceName” assigned in InitializeComponent to instances of class Service1.

6.      ProjectInstaller: The name of the class created by the “Add Installer” command.

7.      Service1: The “ServiceName” assigned to the serviceInstaller1 installer within ProjectInstaller.

It all builds smoothly but when I “Install” the Setup1 project nothing appears in the installed service list (Administrative ToolsàServices).

Next I tried the “installutil” tool from the service project’s bin\Debug folder. The first time I executed it with the command line “installutil *.exe” because I’m lazy. This results in the cryptic error message “Exception occurred while initializing the installation: System.ArgumentException: Invalid directory on URL..”

A much better error message might have been: “Installation file not found: *.exe”. It seems that installutil doesn’t expand wildcards.

Trying again with an explicit filename, “installutil WindowsService1.exe”, worked much better. It puts up an account credentials dialog because the default Account property of the serviceProcessInstaller1 component has a value of “User”. When I entered my user name without a preceding domain name the installation failed, but at least it failed with a good error message. Trying again with a “domain\username” succeeded and now I have a “Service1” showing up in the service list (don’t forget to hit refresh).

Now to work backwards and figure out how to make the production service work:

1.      Ran “installutil /u WindowsService1.exe”.

2.      Changed the Account property of serviceProcessInstaller1 to “LocalService”.

3.      Ran “installutil WindowsService1.exe”

That got rid of the account credentials dialog.

1.      Ran “installutil /u WindowsService1.exe”

2.      Rebuilt the Setup1 project

3.      Verified Service1 was not installed

4.      Ran “Install” on the Setup1 project.

Silent failure.

Manually added “Primary output from WindowsService1 (Active)” to each Custom Actions category in the Setup1 project:

1.      Select the Setup1 project in the Solution Explorer.

2.      Click on the Custom Actions icon in the Solution Explorer toolbar.

3.      Right click on “Custom Actions” and select “Add Custom Action…”

4.      Expand the Application Folder (double click)

5.      Select “Primary output from WindowsService1 (Active)”

6.      OK.

7.      Rebuild and test.

That does it.

 

 

Comments

I could start a service with InstallUtil.exe, having changed classes names and started at the services viewer.

Your article helped me a lot.
Thanks.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)