2019-08-18

1: Any Windows Service in C#, Without Visual Studio

<The previous article in this series | The table of contents of this series | The next article in this series>

Any Visual Studio IDE or any IDE is not necessary at all for creating any C# Windows service.

Topics


About: C#

The table of contents of this article


Starting Context


  • The reader has a basic knowledge on C# programming.

Target Context


  • The reader will understand how to create any Windows service without any IDE.

Orientation


Hypothesizer 7
I want to create a Windows service.

In fact, I once created a Windows service with C++, making use of Win32 API, long ago. But is that still a preferable way?

As I have searched the internet, I have found many explanations on how to create any Windows service with C#, using a Visual Studio IDE . . .

Well, I do not use any Visual Studio IDE or any IDE, and I do not want to begin to use any now.

Why? Well, there are many reasons. For one, I do not like the source file editor, which I am forced to use: the source file editor is crucial for development experience, and I want to use my favorite editor, which is 'vim'. For another, I do not like any IDE-generated code, specifically unnecessary baubles that are gratuitously added: I want my code to be as I intend. For another, I do not like the heaviness of a typical IDE: my computer is not as fast as such heaviness does not matter.

Anyway, it should be OK if I just write necessary code in necessary files.

Is it tedious? In fact, it has turned out that it is quite easy.


Main Body


1: How to Create Any Windows Service Without Any IDE


Hypothesizer 7
In order to create any Windows service, I do not need any IDE.

This is a minimal Windows service.

theBiasPlanet/officeWindowsService/programs/OfficeWindowsService.cs

@C# Source Code
namespace theBiasPlanet {
	namespace officeWindowsService {
		namespace programs {
			using System;
			using System.ServiceProcess;
			
			// Register this Windows service by this command.
			// sc create OfficeWindowsService start={auto | demand} binpath="%path%"  obj=%the computer name%\%the user name% password=%the user password%
			public sealed class OfficeWindowsService : ServiceBase {
				public static void Main (String [] a_argumentsArray) {
					OfficeWindowsService l_officeWindowsService = new OfficeWindowsService (a_argumentsArray);
					if (Environment.UserInteractive) {
						l_officeWindowsService.OnStart (new String [] {}); 
						Console.Out.WriteLine ("### Press any key to stop this Windows service.");
						Console.Read ();
						l_officeWindowsService.OnStop ();
						Environment.Exit (0);
					}
					else {
						Run (l_officeWindowsService);
					}
				}
				
				public OfficeWindowsService (String [] a_argumentsArray) {
					ServiceName = "OfficeWindowsService";
				}
				
				~OfficeWindowsService () {
				}
				
				protected override void OnStart (String [] a_argumentsArray) {
					base.OnStart (a_argumentsArray);
				}
				
				protected override void OnStop () {
					base.OnStop ();
				}
			}
		}
	}
}

Is that it? Yes, that is already a workable Windows service.

The initialization is written in the 'OnStart (String [] a_argumentsArray)' method; the termination is written in the 'OnStop ()' method.


2: Registering the Windows Service


Hypothesizer 7
This command registers the Windows service, with the Windows service user name and the password specified (when 'LocalSystem' is the user, the password is unnecessary).

@cmd Source Code
sc create OfficeWindowsService start=demand binpath="%path%" obj=%the computer name%\%the user name% password=%the user password%


3: Setting Some Arguments to the Windows Service


Hypothesizer 7
I want to set some arguments to the Windows service. I mean, the Windows service should take the specified arguments whenever it is started.

As I looked at the Windows service setting dialog, I found an text box labeled "Start parameters". However, after I had entered some arguments there and closed the dialog, the arguments are not preserved. . . . What is this setting item? . . . It has turned out that the setting item is for passing the arguments one time, which is not what I want.

After all, the arguments should be specified in the Windows service registering command, like this.

@cmd Source Code
sc create OfficeWindowsService start=demand binpath="%path% %argument0% %argument1%" obj=%the computer name%\%the user name% password=%the user password%

My Windows service can accept the arguments as the 'Main (String [] a_argumentsArray)' method arguments, not as the 'OnStart (String [] a_argumentsArray)' method arguments.


4: Writing Logs to the Windows Event Logs System


Hypothesizer 7
In order to write logs to the Windows event logs system, I have to create the event source in the Windows event logs system, which is a one time job that can be done by a separate program.

In fact, I have created this program.

@C# Source Code
namespace theBiasPlanet {
	namespace windowsEventLogSourceCreateor {
		namespace programs {
			using System;
			using System.Diagnostics;
			
			public sealed class WindowsEventLogSourceCreateor {
				public static void Main (String [] a_argumentsArray) {
					try {
						String l_eventLogSourceName;
						String l_eventLogSourceCategory = "Application";
						if (a_argumentsArray.Length < 1) {
							throw new Exception ("The arguments have to be these.\nThe argument 1: the event log source name\nThe argument 2: the category of the event source (the default is 'Application')");
						}
						l_eventLogSourceName = a_argumentsArray [0];
						if (a_argumentsArray.Length > 1) {
							l_eventLogSourceCategory = a_argumentsArray [1];
						}
						if (!EventLog.SourceExists (l_eventLogSourceName)) {
							EventLog.CreateEventSource (l_eventLogSourceName, l_eventLogSourceCategory);
						}
                        Environment.Exit (0);
                    }
                    catch (Exception l_exception) {
						Console.Error.WriteLine (l_exception);
                        Environment.Exit (1);
                    }
				}
			}
		}
	}
}

Then in the Windows service, any log is written, like this.

@C# Source Code
			using System.Diagnostics;
			
					EventLog.WriteEntry ("The service is starting up.", EventLogEntryType.Information);


5: So, What Has Happened to 'ProjectInstaller'?


Hypothesizer 7
In fact, 'ProjectInstaller' is unnecessary (and useless) for my installing the Windows service with the 'sc.exe' command: it is for installing the Windows service with the 'InstallUtil.exe' command.

Although there are some people who claim that the 'InstallUtil.exe' command should be used, I do not feel any bit of necessity to use 'InstallUtil.exe'.


6: The Conclusion and Beyond


Hypothesizer 7
Now, I seem to understand how to create any Windows service without any IDE.

It is quite easy.

And it is quite pleasant to have code that is not obfuscated by any IDE.

In fact, this article is a preparation for creating an office (LibreOffice or Apache OpenOffice) Windows service.


References


  • N/A. (N/A). Sc create | Microsoft Docs. Retrieved from https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create
<The previous article in this series | The table of contents of this series | The next article in this series>