services|window|進階 Now that all the necessary architecture is in place, you can add some functionality to the service. As an example, I'll show you how to build a file-monitoring service that monitors the local file system and notes important activity by presenting the data with a custom performance counter.
The ServiceBase class provides a couple properties all services should implement. ServiceName is the name your service uses to identify itself to the system and to applications that want to start it programmatically. For this example, the ServiceName property is "File Monitor Service." Another property is CanPauseAndContinue—set this to true so your service can support pause and continue functionality.
The OnStart() function performs the necessary initialization to start file monitoring as well as create the custom performance counters on the local system if they haven't been created already. The .NET Framework monitors local file system changes by implementing the FileSystemWatcher class, defined in the System.IO namespace, which allows you to specify handlers for file change notification events. In this case, you're interested in files that are created, changed, deleted, or renamed. Because you want to monitor file changes only on the local file system, you must enumerate all the defined drives and create a FileSystemWatcher object only on fixed drives. But the .NET Framework (as of this writing) doesn't contain any special functions to do this. So you must invoke the GetDriveType() API call defined in kernel32.dll on each drive in the array created from the call to GetLogicalDrives(). You can create a small class called PlatformInvokeKernel32 to wrap the API and call GetDriveType() easily:
public class PlatformInvokeKernel32
public static extern int
GetDriveType (string lpRootPathName);
This code simply forwards all calls using PlatformInvokeKernel32.GetDriveType() to the associated function in kernel32.dll. To get the drive type for each drive in the array, check the value returned from the call to the enumerated type win from the Microsoft.Win32.Interop namespace:
string drives = Environment.GetLogicalDrives();
// create filesystem watchers for
// local fixed drives
foreach (string curDrive in drives )
(curDrive) == win.DRIVE_FIXED)
// create a FileSystemWatcher
Now that you've created the FileSystemWatcher objects, you must implement the event handlers for the four file notification events: creating, changing, deleting, and renaming files. You'll create performance counters that convey information to the user visually—one for each event. For more information on file notification event handlers and creating performance counters, download the code that accompanies this article. To create a performance counter, use the PerformanceCounter class specified in the System.Diagnostics namespace. When you call the file change event handler, it simply increments the proper performance counter by 1:
private void OnFileChanged(Object source, FileSystemEventArgs e)
The ServiceBase class also enables the service designer to create custom commands that the Service Control Manager can send to the service. This is an overridden but optional function named OnCustomCommand(), which I mentioned earlier. It contains a single parameter, an integer, that signifies the custom command to run. One thing you need to keep in mind: The command integer must be a value between 128 and 256; all other values are reserved by the system. For the file-monitoring service you're building, you create four custom commands to reset the counter data for each of the performance counters back to zero. The PerformanceCounter class doesn't support a "Reset" function specifically, but you can accomplish this easily by decrementing the counter by its current value (see Listing 1).