Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How To Create a NT(Win) Service Using C++ with Managed Extensions

0.00/5 (No votes)
26 Jul 2002 1  
This article explains how to create a NT Service also known as a Windows Service using C++ with Managed Extensions.

Sample Image - ManC_WinService.gif

Introduction

This article explains how to create a NT Service also known as a Windows Service using C++ with Managed Extensions. Prior to the .NET Framework, creating NT Services were a tedious and detailed process. It entailed creating a specific Main function that connected to the Service Control Manager (SCM), implementing several methods with certain signatures so that the SCM could call your services� functions. To say the least, it was not for the beginner at all, and an intermediate person could very well become advanced after 1 NT Service project, after going through all the pitfalls, error traps, design decisions and just plain old C++ �syntactics.� I have written many Services to know that the .NET Framework completely simplifies this process; and this article will prove it too you.
Steps Involved with writing a NT Service using regular Winapi and C++

The Tefulataat Service is a Windows Service that plays a Morning Prayer at 9:00am, an afternoon prayer at 3:00pm, and an evening prayer at 9:00pm. These prayers are MP3 files recorded on the drive. The Tefulataat makes use of a Timer object from the System::Threading namespace to work like an alarm clock and kick the Prayers into action. The MP3 files are played using the DirectShow object of the DirectX libraries that are standard among Win2k and up systems. There is not too much error handling, as this article just explains how to create a Windows Service using C++ with Managed Extensions. Now let�s get to the gold shall we? The methodology I will use is a two step approach. When creating Windows Services, you must remember, that the service may always be running, the user does not start it and stop it per say, and also that there is no User Interface for the Service itself. This means that you can�t just display a message box when an error occurs. You can write to an event log, write to a separate file or use some other means which you can access it logs later after the event has taken place already. It also means debugging the Windows Service after its installed is not as simple as placing a break point on code and stepping through it. So how do we handle these concepts? Step one. The first step is to create a simple Windows Application first with all the functionality behind it. Step through the code, debug it and then after all programmatic, syntactical, and logical errors are fixed or handled, you can move your code to step two. I cheated a little bit for the windows::form object, I used VB.NET to create the User Interface, and I translated the Form properties in VB code to C++ with Mananaged Extensions (Using C# would have been a lot easier too, however I just wanted to use VB).
Sample Image - ManC_WinService.gif Windows App in Man C++ with Service Methods for Step One.

Step two is placing your code inside the Windows Service code, and adding event Logging to help with debugging. (Another way to easily generate the template service code is to generate it in C# and just translate the code into C++). Let�s delve more into this step here: The Windows Service C++ source code starts this way. You must first include your standard C libraries and your .NET libraries or assemblies at the top of your Header or source file as done with this snippet of code here:

The #include statements actually open up the files inside the �� when compiled and compiles those files too. The #using statement tells the compiler to include these assemblies. This assemblies are referenced and are needed for your source file to compile. For all C++ Man Ext, you must reference the mscorlib.dll, and for the Windows Services, you must reference the System.ServiceProcess.dll as well. The other assemblies are needed according to what functionality you use in your application. Next, to save you typing, you can include namespaces. Namespaces provide a way for you to access members that are logically grouped together using a naming convention like this:

For example, if I wanted to access an Xml Document object in C++ the syntax would be: XmlDocument * pXmlDoc = new XmlDocument(); With the namespaces. However, without the namespaces, I would have to type the complete library and naming convention out as thus: System::Xml::XmlDocument * pXmlDoc = new System::Xml::XmlDocument(); Namespaces also allow you to distinguish between naming conflicts in case you have two type of objects that exist in two different namespaces, you could distinguish between the two by including its top level naming convention. Next, I create a namespace for my application, and set up its class based off of the Interface I inherited:

All of .NET Windows Service Applications inherit from the ServiceBase class. This class has all the functionality designed for the .NET CLR to communicate to the SCM when your application runs. All you have to do in override the methods defined as overridable, or abstract for the ServiceBase class and add your functionality. Notice the �__gc� keyword. This keyword tells the compiler that this class is a Managed C++ class and must have the �/clr� included when compiled. In effect this means that the class will participate in all the .NET Clr functionality, including Garbage collection process, memory management, and etc. All the previous code was placed inside our Header file. Now let�s deal with the source file. In our source file we make sure we include our Header file so that the Source code has all the libraries needed to compile.

Note: I also include the �vcclr.h� file. This file contains necessary functions to convert System::String * objects to Native char * objects and other useful functions for converting .NET managed types to Native C++ types. Next Inside your constructor, you want to initialize your components:

Inside the Constructor we make a call to the InitializeComponent() method. This method creates an Eventlog pointer and sets the EventLog type to Application, and its EventLog Name to �Tefulaat�. The next line of code creates an EventLogTraceListener pointer. This pointer points to a type of TraceListener object. The TraceListener object of the Static Trace object can now add another TraceListener in order to keep track of all Traces inside a program. A Trace is a way to write out messages as the application executes. In the System::Diagnostics namespace, there is a static Trace object the executes with every application that can write messages to a Listener. A listener could be a text file, Event log, or any object that you define that implements ITraceListener. After the TraceListener, we create a TraceSwitch, to allow us to get/set a Trace Level. The developer can determine what messages write to a Listener based off of a particular Trace Level set either through code or through a Configuration File. The Next line of code gets the Configuration file Reader pointer. All the lines of code up until now just set up our environment for an EventLog to write out error messages to, as well as a pointer to our configuration file reader. These lines of code are not necessary for the service, however, they help manage the application better.
Event Viewer with Tefulaat Trace Messages written to Event Log

The next line of code I want you to pay attention to is the line that says: this->ServiceName = S�Tefulaat�; This line is very important. This name is the name that the Registry creates inside the �Services� key under the �CurrentControlSet� key. This is the same name (letter casing is important also), that you will use to run the service if using �Net Start� or �SC�. This is also the same name you will use when you create the �ServiceInstaller� and �ProcessInstaller� later in this example. If this name in all these different objects differ in any way, you will spend a whole week on this article! Not fun at all! Once you have set up your Service Name, which is the only thing you need to do in the constructor for a Service to work, we can take a look at our next coding section. The OnStart method:

The OnStart method is called by the SCM. Here you can receive string arguments or just a default with no arguments. In this procedure, a pointer to the TimerCallback (basically a delegate) is created by assigning it to this class and assigning the method to call back as the �TefulaatTimer_Tick� method, which is declared in the Header file. Next we create the pointer to the Timer object and set its initial properties to the timerdelegate, this class, an infinite start time (meaning don�t start the timer yet), and the interval in seconds to wait for the method delegate to be called again in milliseconds. Next we call the Change method which reads the configuration file and sets the Timer Interval to the configuration file key=value of �TefulaatTimer.Interval�, and starts the Timer. The OnPause, and OnContinue methods are not implemented here, but they too are called by the SCM. You could imagine that we could just stop the timer here and restart it according to their respective procedures. The OnStop method is defined as thus:

We just stop the timer. Inside our TefulaatTimer_Tick method in part:



This is where all the gold of the code is. In this method we get the current Date and Time and check the time against the Configuration Settings. If the Time is at the designated time inside our Configuration settings we then read a list of Xml elements and parse through an XmlDocument to get all the prayers to play for that specific time. The mp3 Files are loaded inside the DirectShow Object and played accordingly. The rest of the code is inside the source files.
PlayIntro method in part

The Last two things we need to do is create a main entry point for our application and create an Installer. (Actually, we don�t need to create the installer, because we can always install it manually- in which in Win XP Pro you have to for some reason or another.) The main entry function looks like this:

remember a Windows Service file is a regular Exe application that has a Class that inherits from the ServiceBase class, thus we need to have an entry point for our application. In actuality, I only need to add the eventlog once, the more times you add it, the more times it will write to your event log. The only thing you should pay close attention to is the two lines of code that states: System::ServiceProcess::ServiceBase * ServicesToRun[] = { new TefulaatService::Tefulaat() }; ServiceProcess::ServiceBase::Run(ServicesToRun); These two lines call your constructor for your class or classes if you want to have more that one Service in your application, and registers your class(es) to run as a Service(s), respectively. When your service runs as a LocalSystem object, when the Win2K or Win XP runs the services, this main entry runs which initializes your service. Now, compile the application using the �/clr� option and link all your obj files and you have a Windows Service ready to run. Installation: Ok, I have a service but how do I install it???? There two basic methods to install a Windows Service, automatically using some scripted method or the ServiceInstaller, or manually. From my beginnings, I could not get the Managed C++ Service App to install correctly for Win XP Pro, thus I installed it manually (Kind of�) Using the ServiceInstaller and ProcessInstaller. For every service that you create in your application, you will need to have a ServiceInstaller object, and a ProcessInstaller object. These two pointers exist inside a class that inherits from the System::Configuration::Install::Installer class. Here�s the Header info:

One thins to notice here is the [RunInstaller(true)] attribute placed on the class. This flags the installutil.exe program to run this Installer class in order to install the Service. Otherwise the installutil.exe program will just ignore the service install all together; meaning that the service will not install. Now the Source File:



The code to pay attention to is the code inside the InitializeComponent() method. A new serviceProcessInstaller is created. Then a new ServiceInstaller is created. The Process Installer creates a transacted process to install services. If one service fails, then the whole process will roll back its installation if more than one service is attempted to be installed. The Service Process can be run as a particular user, localSystem, or other Service Account just like any other Windows Service. Use the Service Process Installer to set this information up. The Service installer actually installs the Service. A registry is creates along with the Display name and Service name. Remember, the service name must be the same as the Service name you created inside the actual service otherwise this installation won�t work correctly. To install the Windows Service, run the command line utility that comes with the .NET Framework: installutil.exe �MyService.exe� To start the Service you can type �Net Start Tefulaat� or go to the control panel->Administration->Services and look for the Tefulaat Services click to high light then press start. Manually Installing the Service (A Very Dangerous Hack): For some reason or the other, the Managed C++ Win Service application won�t install with the installutil.exe program. Thus I had to manually install it. One way to do it is to create a C# InstallerClass, and a C# Dummy Service. Compile it and set all the properties you want as far as if it�s a LocalSystem object, its Service Name = �MyC++ServiceName� and the display names and etc. Compile and build this C# Dummy service with just the procedure sigatures and its installer class as outlined earlier. Run the installutil.exe �MyC#DummyService.exe� command. Next run �Regedit or Regedt32� and go to your currentcontrolset hive, then your system->services hive. Next search for the �ServiceName� hive you gave your service and change the path that the executable is pointing to, to your Man C++ application binary file. Compiling: When you compile from the command line, Compile your InstallClass.cpp with your ServiceClass.cpp make sure you link your InstallerClass.obj before you link your ServiceClass.obj file, I have found inconsistencies when linking the other way around. Believe it or not, that�s all folks! Author�s Note: To make the Mp3 files play make sure the 3PM.xml 9PM.xml 9AM.xml and Intro.xml files all point to valid mp3 files inside their contents on your hard drive. Also make sure the Configuration File points to the correct hard drive paths for the xml files inside its contents. The Configuration file should be named �Filename.exe.config� and should be in the same directory the exe file is in. If your are using Visual Studio.Net, you will also need the DirectX include files as well as their libraries If you are using a text editor, you will need the same also. Upcoming� How to control the service using a Service Control manager Client Application -Dwight Goins, MCSD, MCT, MCP .NET DNGoins@aol.com 2002/26/07

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here