Learn How to Create Dual Mode Windows Services
Introduction
Windows Services provides a great way to run processes continuously in the background; however, debugging them can sometimes be a challenge. The debugging problem is exaggerated when you have startup issues. This can be easily solved by creating a dual mode service. A dual mode service can run as either a Windows Service or as a console application. To get started we first create a standard Windows Service project in Microsoft Visual Studio as shown below:
Figure 1 - Project Type
After creating the basic Windows Service project it is a good idea to create a single class which is used to startup and shutdown. Generally, I recommend using the Constructor for startup and the Dispose method for shutdown and cleanup. This class which I usually call manager is the initial launching point for the application. All other threads, timers, objects, etc will need to be launched from this class. This is important since we will be using this class to start the app in both modes. Listed below is a simple manager class which creates a single thread timer to perform work once per second.
class manager : IDisposable
{
private Timer tmrWork;
public manager()
{
tmrWork = new Timer(new TimerCallback(tmrHit), null, 1000, 1000);
}
private void tmrHit(object state)
{
Console.WriteLine("Timer Hit!");
//Perform Work Here ...
}
public void Dispose()
{
tmrWork.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
tmrWork.Dispose();
}
}
Next we will need to modify the Service1.cs
class created in the project to actually use the manager
class and start/stop the service. You will want to
create a private member variable of type manager and create
the object in the OnStart method and Dispose of
it in the OnStop method as shown below.
private manager mgr = null;
protected override void OnStart(string[] args)
{
mgr = new manager();
}
protected override void OnStop()
{{
mgr.Dispose();
}
The basic service itself is almost done minus the install class. As you may know the install class is used to add the service to the Windows Service Manager during the install process. I've included the one below for reference.
[RunInstaller(true)]
public partial class Installer1 : Installer
{
private ServiceInstaller serviceInstaller1;
private ServiceProcessInstaller processInstaller;
public Installer1()
{
processInstaller = new ServiceProcessInstaller();
serviceInstaller1 = new ServiceInstaller();
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller1.StartType = ServiceStartMode.Manual;
serviceInstaller1.ServiceName = "Dual Mode Service 1";
Installers.Add(serviceInstaller1); Installers.Add(processInstaller);
}
}
At this point you can create a Setup Project and add the project output to the custom actions for install and uninstall and this service is ready to go; however, at this point it is not able to be run as a console app. In fact if you do it will simply give an error message stating that it cannot be run outside of Service Manager. To solve this problem we need to make a couple changes. First we need to change the Output Type under Project Properties from Windows Application to Console Application as shown below:
Figure 2 - Output Type
Next, we need to modify the Main method in
the program.cs class to correctly start up in console
mode. To support both modes, the Main
method will need to accept a command line parameter which
will be used to determine which mode to start in. For
this example, the code expects to see zero parameters for
service mode and one for console mode. The snippet
below shows how to modify the Main to accomplish this
task.
static void Main(string[] args)
{
if (args.Count() == 0)
{
//Service Mode
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
else
{
//Console Mode
manager mgr = new manager();
Console.ReadLine();
mgr.Dispose();
}
}
In the first half of the if statement, the
code used to run as a service is unmodified. The
else side creates a new manager class which
launches the process, keeps it running by a
Console.ReadLine(); and cleans up when
the user presses Enter. To debug in console mode, it
is as simple as adding a command line parameter to the
Debug\command line arguments option in the project
properties.
Conclusion
The method for creating a dual mode service simplifys the process of debugging; however, it will not be able to completely eliminate the need for testing as a Windows Service. You should also determine if you actually need console mode to be deployed in the final product. If you do not want console mode to be used outside of development, then you should use conditional compile statements or a command line password. In addition it is a good idea to adapt common routines such as logging which can provide console output in console mode and another type of loggin service mode.
Click here to download the project example.
About the Author
Chris Bennett with Crowe Horwath LLP in the Indianapolis office. He can be reached at chris .bennett@crowehorwath.com>

Comments
Great Article - 2 days late!
Posted by boboliak on 02/09/2010 12:38pmHey Chris, Great article. I wish it had been posted 2 days ago when I had to figure all most of this out myself. I did it in VS2010 Express Beta 2 which has no service project template, so it started as a console application and did not require modification to the output type. Thanks for posting this article!
-
ReplyThanks
Posted by CBennett on 02/16/2010 10:01amGlad you like the article.
Reply