|
Build Your First .NET Windows Service (Continued)
Install the Service
You need to be able to install a service now that you've created it. Add an installer to the AppMonitor project by going to the designer view of AppMonitor and clicking on the Add Installer link on the property tab (see Figure 1).
Clicking on this link adds a ProjectInstaller.vb module to the project, which contains two new components in the designer (ServiceProcessInstaller and ServiceInstaller). The ServiceProcessInstaller component for a Windows Service project holds the account type (LocalSystem, LocalUser, User, and so on) and credentials that the service will run under. The ServiceInstaller component holds information written to the Registry (HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services) about the service. This includes the name, display name, list of services depended on, and startup type (automatic, manual, or disabled—manual is the default). If your project contains multiple services, each service should have a separate ServiceInstaller component. You can also use the install and uninstall events of this component to perform additional installation work for your service.
Once these components are added and the project is compiled, the RunInstaller attribute is set to True. Only those classes with this attribute set to True will be installed when running the installer (see Listing A to view the auto-generated code and events that you can hook into within the ProjectInstaller.vb module).
You can install the service by going to the \bin directory underneath the AppMonitor project directory and running the InstallUtil program. InstallUtil is a .NET Framework utility that runs the .NET installer on the target executable (the .NET Framework directory should be part of the path by default after installing the .NET Framework). Use this command to install the AppMonitor service:
InstallUtil AppMonitor.exe
You can also use InstallUtil to uninstall the service, as long as it is stopped:
InstallUtil AppMonitor.exe /u
If you've loaded multiple versions of the .NET Framework, you need to use the framework version of InstallUtil that matches the .NET Framework you compile to. You can find InstallUtil.exe in the framework directory:
%WINDIR%\Microsoft.NET\Framework\vx.y.zzzz
Take a look at the command window result of running InstallUtil on the AppMonitor project. InstallUtil also logs this information in a file called <service_name>.InstallLog.
One last thing to note about compiling and installing Windows Services is that if you install the service from the project's \bin directory, you won't be able to recompile the service project while the service is running, because Windows will have the service executable locked.
Create a Service Wrapper Class
Now that you've created and installed the service, it's time to start work on interfacing the desktop client applications with the AppMonitor service. The easiest way to do this is by implementing the OnCustomCommand event within the service, then having each application send monitoring commands to the service (which I'll discuss in a moment). A Windows Service can only receive integer values and cannot return values. A poorly documented user service command restriction says that service custom user commands must be in the range of 128-255. Windows reserves values under 128 for system-level commands. You'll get a vague Win32 exception if you attempt to send a custom service command out of this range:
Cannot control service
<service_name> on machine ?.?
The easiest way to provide an interface with the AppMonitor service is to create a wrapper class that all of the desktop applications can use. The purpose of the wrapper class is to obfuscate the details of how and where the monitoring service is implemented. It also makes it easier to change the way the monitoring service is designed, without affecting any of the client applications. Create a MonitorWrapper class that contains enumerations for the various monitoring command codes, as well as a single method (MonitorThis()) that external applications can use to send monitoring commands (see Listing 2).
Back to top
|