Foreword
Services in Windows manage almost everything: from supporting the system afloat to parental control services. In the Task Manager, there is a tool for reviewing and stopping / starting them, not to mention a separate utility built into Windows. But what if you need to integrate such a tool into your program? Where to get all this information? How to manage services? I'll tell you how I did it in C # and what difficulties I encountered.
How it all began
I am a novice C # application developer. More precisely, I was a beginner about a year ago. Now I think that with a special desire I can fully develop quite complex things. Well, it's not about that. In general, I needed to create a utility that
correctly displayed and owned the most necessary functionality for managing services. Something like the existing feature in windows manager.
How everything was painted
The interface did not threaten the wealth and I decided to stop on the toolbar and the list in which the services will be displayed. The latter was chosen DataGridView, because it displays information in a column view, which was very convenient for me, and also has some amenities for users (sorting, for example).
On the toolbar, there were about 6 buttons that controlled the selected services.
There were no difficulties at the stage of drawing the interface, and it was successfully completed in just a few hours.
How everything was developed
Well, first of all, two mechanisms were needed: the first, which found all the services registered on this machine and information about them, and the second, which would correctly drive all this into a DataGridView. With the second problems should not arise. But with the first I had to suffer (and as it turned out, it was the most difficult part of the development). More about him ...
')
As planned, it was necessary to find in the system the following information about each service: the name, and not the system, but the user; service description; her condition; startup type; the path to the file and on whose behalf it was launched. There were no problems with the name - DisplayName from the ServiceController class displayed it very correctly. The status is also not very difficult - the Status property from the same class helped a lot. But to find out from whom the service was launched, what type of its launch and where the image is located - I had to go to the registry. Also, in principle, nothing transcendentally complex, but I had to sit longer than on the previous attributes.
Things have complicated
As it turned out, the stumbling block was the description of the service, understandable to the user. Starting to look for ways to get it, I realized that neither ServiceController, nor even the registry can give a normal description. Often in the registry in the Description line is a link to the dll library and the line number in which the library contains the description of the service. And since C # still does not know how to dynamically take information from a dll, every time you update the list, you had to look at the registry, take the link and the line number, go to the library, load it, search for the line, copy the description, and unload the library back. As expected, it had a terrible effect on speed. The first launch of such a modest program takes about 5 seconds (although subsequent updates are made fairly quickly).
How it all ended
Everything else (controls, displaying information in a DataGrid, convenience for the user in the form of returning focus and sorting into place after updating the list, etc.) was quite simple. By trial and error (and endless rustling in the network) this was all achieved. As a result, the utility turned out to be quite convenient and some even agreed to use it as a test instead of the standard service in the task manager.
Here is the screen of the running program

The code (even the main part) is quite voluminous, here is the part about searching for the description information:
val = targetKey.GetValue ("Description");
if (val == null)
row [1] = ""; // No Description
else
{
string s = (string) val;
Match m = Regex.Match (s, @ "^ [@] (? (. *)), \ S * - (? (\ D *))");
if (m.Success) // Check if the string is a resource reference
{
string w1 = m.Groups ["path"]. Value; // dll path
// Replacing the system variable% SystemRoot% on the way (if any)
string w2 = Regex.Replace (w1, @ "% SystemRoot% |% windir%", SystemRootPath, RegexOptions.IgnoreCase);
// Replace the% ProgramFiles% system variable in the path (if any)
string DllPath = Regex.Replace (w2, @ "% ProgramFiles%", ProgramFilesPath, RegexOptions.IgnoreCase);
int ID = Convert.ToInt32 (m.Groups ["id"]. Value); // resource ID
// Load the required dll
IntPtr hndl = DllInterop.LoadLibrary (DllPath);
// Get the description
row [1] = DllInterop.LoadStringDll (hndl, ID);
// unload dll
DllInterop.FreeLibrary (hndl);
}
else
row [1] = s;
PS I think (practically sure) that the “inveterate” developers and programmers will not find anything new for themselves, but I think it will be informative for people who have not worked with Windows services in C # before. If you need any parts of the code or even the program itself, then contact it will be very nice to help.