Windows7 Trigger Start Services – Part 2: Building a Trigger Start Optimized Service
In the last post Windows 7 Trigger Start Services – Part 1: Introduction, we introduced Windows7 Trigger Services as a great way to optimize your services to have better performance and improved security. In this post you will learn how to convert a standard automatic-start service to a trigger-start service that starts up only when a certain event occurs in the system. We’ll use a WPF application (obviously managed code) that registers and monitors a service (also implemented using .NET). To bridge between the .NET world and the native Win32 APIs that we saw in the previous post, we use a C++/CLI interoperability layer.
This sample application has 3 parts:
- A C++/CLI interoperability layer that provides a regular and easy .NET API to the controller application
- A WPF controller application that lets you register and run the service
- A simple .NET service that looks for a USB storage device (disk on key) and on it, a specific folder named “ToCopy” from which to copy files to your local “C:\FromUSB” folder
The following image illustrates the solution structure.
Let’s start by reviewing the .NET Service code implementation. This is a simple Windows service written in C#. The purpose of this service is to copy pictures automatically to your local hard-drive- “c:\FromUSB” from the USB storage device that is plugged into your computer.
The service implementation can be found at USBService.cs. This class inherits the ServiceBase base class and overrides the OnStart and OnStop methods. This class has a DoWork method that actually does all the copying of images from the USB disk to your local drive. The DoWork method writes to a log file that we will be monitoring.
The real interesting part of the service implementation is the OnStart method. This method is called once the service is started. Notice that the first line of code checks whether the service is configured as a trigger start service. If the “if” statement returns false, we create a new instance of a timer and have it poll every 5 seconds. Before Windows7, this was the only way to implement such a service, that is, by regularly polling the system to check for a USB device. Therefore, the service needs to run 24x7 to poll the system. This is highly wasteful of resources and keeps the system from transitioning to a low-power state, increases the application attack surface, among other negative things.
But, with Windows7, you can configure such a service with a USB device arrival trigger. This means that the service will not run until a USB device arrives, specifically a USB generic disk device. We’ll get to that part of the solution in a second, but for now, if you look at the OnStart method, you will notice that we check whether the service is configured as a trigger start service; if it is, we simply call the DoWork method on another thread, as shown by the following code snippet. This should work just fine because the service is NOT running, and will start to run only when the trigger happens. And then it will not default to the timer, but rather use the thread pool to queue the work.
protected override void OnStart(string[] args) { if (ServiceControl.IsServiceTriggerStart(ServiceName)) { ThreadPool.QueueUserWorkItem(_ => DoWork()); } else { _timer = new Timer(_ => DoWork()); _timer.Change(0, 5000); } }
The ServiceControl namespace contains the C++/CLI interop layer. This layer uses C++/CLI as the binding element between the native API and the WPF application. The main ServiceControlInterop.cpp file contains all the functionality that we need and that is used by the WPF application. For example using the controller application we can use AddService(…) or RemoveService(…) to add or remove a service respectively. We can also configure the service as a trigger start service for either a USB device arrival or first available IP address by using SetServiceTriggerStartOnUSBArrival or SetServiceTriggerStartOnIPAddressArrival respectively. Reviewing both function implementations reveals that basically both are following identical paths. They:
- First, use OpenSCManager to get a handle to the Service Control Manager (SCM)
- Then use the SCM handle OpenService, to get an actual service handle that we wish to configure
- Finally call ChangeServiceConfig2 to set the specific trigger
All this was explained in detail in the last post (Windows7 Trigger Start Services – Part 1: Introduction
You can download the code sample for this application. Note that you will have to run Visual Studio as administrator (see image below) because you will need to register, start, and stop services. . You will also need to Windows 7 SDK to compile the C++ part of the solution.
When compiling and running the default solution (the WPF application) you will see the following image.
This is the main WPF controller application. From here, you can create the service by clicking the Create Manual button.
Next, open the Services Window by typing “Services” in the Start Menu search box. You should see the Service window. Locate the USBCopyService; it should appear as in the following image.
Click the Run button and then the Refresh button in the Services window, or just press F5. You will not notice a great deal of change, but the USBCopyService changed from Manual to Started, as shown in the following image.
A second look at the actual application reveals the service activity in the log file. As you can see in the following image, the services awaken every 5 seconds and poll the system, looking for USB devices:
Click the Stop button to stop the service and then click the Delete Service to delete it. Now click the Trigger Start button to register and configure the service as a trigger start service that is triggered once a USB Generic disk arrives. If you check the Service window, you will see the USBCopyService listed as “manual” where in reality it is configured as triggered start service (there is just no graphical representation of that).
If you plug in a USB disk with a “ToCopy” folder the service will kick into action and copy the files to c:\FromUSB. Not the best implementation, but hey, it is only a demo. The following image shows a single line in the log file because the service actually ran only once; it executed the DoWork method and then quit. It didn’t run and poll the system every 5 seconds and didn’t waste resources or become a security liability.
To conclude
Developing a service with Windows 7 trigger start service in mind might be a little more difficult than a regular “auto-run” service that just runs in idle from boot to shutdown. But in practice, all it takes is only a few lines of code, no more. And these few lines of code can have a very big affect in terms of resource consumption and security. So the next time you build a new Windows Service, try to incorporate triggers.
You can learn about Windows 7 using the Windows 7 Training Kit for Developers or by viewing Windows 7 videos on Channel 9.
You can also get hands-on experience for Windows 7 Trigger Start Services using the Windows 7 Online training that is part of the Channel 9 Learning Center
Written by Yochay Kiriaty on October 27th, 2009 with no comments.
Read more articles on Windows 7 Training Kit and Trigger Start Services and Windows 7 Trigger Start Services and otherSoftware and windows 7 and .Net and Performance and Microsoft.















