Recent

Author Topic: [Solved] list all Windows services.  (Read 2451 times)

jw

  • Full Member
  • ***
  • Posts: 126
[Solved] list all Windows services.
« on: May 29, 2022, 11:37:44 pm »
Windows 10 x64
Lazarus 2.0.10
FPC 3.2.0

The starting point for all service related stuffs .
https://forum.lazarus.freepascal.org/index.php?topic=13423.0
https://wiki.freepascal.org/ServiceManager

Menu-->System-->Drop a tservicemanager instance on the form.  My instance is named ServiceManager.

So I'm trying to simply list all the services in Windows, and their state(running, stopped, starting etc) to a tmemo.  One of the Windows API calls that I think I'm trying to get at via the service manager is EnumServicesStatusA.  But I'm not sure if I've found the correct pascal servicemanager.sub_commands, nor do I know how to properly process TServiceEnteries and or TComponentEnumerator's in order to make simple strings for them for tmemo.   

Here's some code that's so bad it's really not worth sharing...

Quote
procedure TForm1.Button1Click(Sender: TObject);
var
  Num_of_Services: longint;


begin

  servicemanager.Access := $0001;
  ServiceManager.Connect;
           

     //Num_of_Services:= servicemanager.InstanceSize;  //nope that didn't return the correct number of services

     //Num_of_Services:=servicemanager.ComponentCount;  //This always returned 0?
 


   
for count :=0 to Num_of_Services -1 do
     begin
 
          memo1.text:= memo1.text +  try to do something to do with servicemanager.GetEnumerator or
          maybe servicemanager.Services;  not really sure?

     end;

  ServiceManager.free;

end;               



It think the hardest part for, me at least, is that I know what bytes, words, integers, strings, the basic data types are.  I can often drop to the API's themselves and overcome Microsoft's strange datatypes, at least sometimes, as hwind etc are just integers.  I do really hate when a Microsoft API return a pointer to the data I need, which happens in this case, but I think that's taken care of an repackaged by tservicemanager.  But if anyone can tell me how to get good at figuring out what makes up the ever going PAscal datatypes I keep seeing, such as TComponentEnumaerator's and TserviceEnteries etc, then let me know.
« Last Edit: June 07, 2022, 05:28:42 pm by jw »

friend

  • Guest
Re: list all Windows services.
« Reply #1 on: May 30, 2022, 02:03:42 am »
Hi. I'm sorry that you use M$ Windows 10.
Unfortunately this class is not well documented. I had to look at the source code in the path:
Code: Pascal  [Select][+][-]
  1. lazarus\fpc\3.2.0\source\packages\fcl-extra\src\win
to understand how to use it to list all services.
I found the property 'Services', its type, and then searched where it is used. Found the Refresh() function. There is a field called RefreshOnConnect that is false by default. Setting it to true will refresh on connect  :)
 
Here's a simple example to list services and their states into a Memo:

Code: Pascal  [Select][+][-]
  1.  
  2. function ServiceStateName (statusCode: Integer): String;
  3. begin
  4.   case statusCode of
  5.        SERVICE_STOPPED: Result := 'Stopped';
  6.        SERVICE_RUNNING: Result := 'Running';
  7.        SERVICE_PAUSED : Result := 'Paused';
  8.   end;
  9. end;
  10.  
  11. procedure TForm1.Button1Click(Sender: TObject);
  12. var
  13.   Num_of_Services: longint;
  14.   i: Integer;
  15.   entry: TServiceEntry;
  16. begin
  17.  
  18.   servicemanager1.Access := SC_MANAGER_ALL_ACCESS;
  19.   ServiceManager1.RefreshOnConnect := True;
  20.   ServiceManager1.Connect();
  21.  
  22.   Num_of_Services := serviceManager1.Services.Count;
  23.  
  24.   for i := 0 to Num_of_Services -1 do
  25.   begin
  26.       entry := serviceManager1.Services[i];
  27.       memo1.Lines.Add (entry.DisplayName
  28.       + ' : '
  29.       + ServiceStateName(entry.CurrentState));
  30.   end;
  31. end;
  32.  

You must include JwaWinSvc in your unit's Uses section. There the constant SC_MANAGER_ALL_ACCESS and others are defined. Notice that you don't really need to Free the component if you add it using the form designer.

Quote
I can often drop to the API's themselves and overcome Microsoft's strange datatypes, at least sometimes, as hwind etc are just integers.  I do really hate when a Microsoft API return a pointer to the data I need, which happens in this case, but I think that's taken care of an repackaged by tservicemanager.

M$ Windows API is well made. The data types are well defined; numeric identifiers and their pointers mean that the object is managed by the operating system itself, one does not access the members directly, but by using functions. TServiceManager, for example, is just a class that adds an abstraction layer over native structures and functions.

Quote
But if anyone can tell me how to get good at figuring out what makes up the ever going PAscal datatypes I keep seeing, such as TComponentEnumaerator's and TserviceEnteries etc, then let me know.

Most of the time I find what I'm looking for by reading the documentation (in Lazarus: Help -> Help), file path: lazarus\docs\chm.
In this case I had to see the source code itself. Using default keyboard shortcuts in Lazarus: Alt + Up, Ctrl + F.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: list all Windows services.
« Reply #2 on: May 31, 2022, 06:37:05 pm »
Code: Pascal  [Select][+][-]
  1. function ServiceStateName (statusCode: Integer): String;
  2. begin
  3.   case statusCode of
  4.        SERVICE_STOPPED: Result := 'Stopped';
  5.        SERVICE_RUNNING: Result := 'Running';
  6.        SERVICE_PAUSED : Result := 'Paused';
  7.   end;
  8. end;

There are several more statuses available, why are you not converting all of them?  At the very least, I would suggest returning statusCode as-is if a match is not found, eg:

Code: Pascal  [Select][+][-]
  1. function ServiceStateName (statusCode: Integer): String;
  2. begin
  3.   case statusCode of
  4.     SERVICE_STOPPED: Result := 'Stopped';
  5.     SERVICE_RUNNING: Result := 'Running';
  6.     SERVICE_PAUSED : Result := 'Paused';
  7.     ...
  8.   else
  9.     Result := IntToStr(statusCode);
  10.   end;
  11. end;

Code: Pascal  [Select][+][-]
  1. servicemanager1.Access := SC_MANAGER_ALL_ACCESS;

Just to nitpick, but SC_MANAGER_ALL_ACCESS is asking for too many permissions that you don't really need just to get the statuses.  All you need in this case is SC_MANAGER_ENUMERATE_SERVICE.  Don't ask for more permissions than you actually need.

Code: Pascal  [Select][+][-]
  1. servicemanager1.Access := SC_MANAGER_ENUMERATE_SERVICE;

Principle of least privilege

Enhance security with the principle of least privilege
« Last Edit: May 31, 2022, 06:43:18 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

friend

  • Guest
Re: list all Windows services.
« Reply #3 on: June 01, 2022, 09:38:38 am »

There are several more statuses available, why are you not converting all of them?  At the very least, I would suggest returning statusCode as-is if a match is not found, eg:

To keep it simple. "Running", "paused", "stopped" are the most common states of services. In case the status is different from those, an empty string will be returned. I mentioned where the constants are defined. If someone is interested in more statuses he can look at the list himself. Either in that unit's source code or Windows API's headers. These constants reflect possible values of Win32 API's SERVICE_STATUS structure's dwServiceStatus member.


Just to nitpick, but SC_MANAGER_ALL_ACCESS is asking for too many permissions that you don't really need just to get the statuses.  All you need in this case is SC_MANAGER_ENUMERATE_SERVICE.  Don't ask for more permissions than you actually need.

Code: Pascal  [Select][+][-]
  1. servicemanager1.Access := SC_MANAGER_ENUMERATE_SERVICE;

Principle of least privilege

Enhance security with the principle of least privilege

Thanks for pointing this out, you're right friend, it is not necessary, and better to use the one you mentioned. Again keeping it simple; and one should look at possible values.
Also reflects the fact that I like control, am not stupid and don't like when computers try to protect me from myself; being "Administrator" on Window$, I will have all these privileges anyway, despite not needing them just to list the services.

This "Principle" is another idea that is part of something called "common sense", just like many things in this area of knowledge. Like the "Single Responsibility Principle" in Object Orientation cr*p. This "Principle" can be summarized in one sentence (one definition I found; others use different words to convey the same idea):

Quote
The principle of least privilege (POLP) requires giving each user, service and application only the permissions needed to perform their work and no more.

This is also part of something known as "common sense", a trait of healthy people.
No need to post two links, let alone such garbage sources -- W*kipedia and M$'s site. Then again, given the state of certain search engines, and the Internet in general, what can one do?

;)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5469
  • Compiler Developer
Re: list all Windows services.
« Reply #4 on: June 01, 2022, 01:45:03 pm »
No need to post two links, let alone such garbage sources -- W*kipedia and M$'s site. Then again, given the state of certain search engines, and the Internet in general, what can one do?

Please hold back your tone a bit. They provide valid information about the principle and only because you already know about it - great for you - does not mean that Remy Lebeau knows that you know about it or that other people that might find this thread might know about it.

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: list all Windows services.
« Reply #5 on: June 01, 2022, 08:04:31 pm »
hello,
with WMI :
Code: Pascal  [Select][+][-]
  1. implementation
  2. uses utilwmi, contnrs;
  3.  
  4. {$R *.lfm}
  5.  
  6. { TForm1 }
  7.  
  8. procedure TForm1.Button1Click(Sender: TObject);
  9. var
  10.   WMIResult         : TFPObjectList;
  11.   f,j               : integer;
  12.   retVal            : String;
  13. begin
  14.   WMIResult := GetWMIInfo('Win32_Service', ['Name', 'State','Status']);
  15.  
  16.   for f := 0 to Pred(WMIResult.Count) do
  17.   begin
  18.     j := 0;  // first entry = Name
  19.     retVal := TStringList(WMIResult[f]).ValueFromIndex[j];
  20.     Memo1.Append('Name : ' + retVal);
  21.     j := 1;  // second entry = State
  22.     retVal := TStringList(WMIResult[f]).ValueFromIndex[j];
  23.     Memo1.Append('State : ' + retVal);
  24.     j := 2;  // second entry = Status
  25.     retVal := TStringList(WMIResult[f]).ValueFromIndex[j];
  26.     Memo1.Append('Status : ' + retVal);
  27.     Memo1.Append('======================================');
  28.   end;
  29.  
  30.   WMIResult.Free;
  31. end;      
       

utilwmi v0.3 is here

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

BobDog

  • Sr. Member
  • ****
  • Posts: 394
List all Windows services 2
« Reply #6 on: June 02, 2022, 05:16:49 pm »
List all windows services is locked. [Mod: unlocked and merged; off-topic posts removed.]
I cannot ask Jurassic Pork to adjust his code so I can try it (I am using geany and console output)
That is
with WMI :
then creating a unit.
I don't really understand the concept of creating a unit to run code, where do you save this unit?
Does it go into the distribution units folder?
Code: Pascal  [Select][+][-]
  1.  
  2. uses
  3. process;
  4. var s:ansistring='';
  5.  
  6. begin
  7. runcommand('c:\windows\system32\cmd.exe',['/c','sc queryex type=service state= all'],s);
  8. writeln(s);
  9. writeln('Pree return to end . . .');
  10. readln;
  11. end.
  12.  
  13.  
Seems to be similar to Jurassic Pork's attatchment
https://forum.lazarus.freepascal.org/index.php?action=dlattach;topic=59497.0;attach=49168;image
To experienced Freepascal people:
Sorry to ask such silly questions.


[Edited to add Mod note.]
« Last Edit: June 03, 2022, 03:33:36 am by trev »

440bx

  • Hero Member
  • *****
  • Posts: 4025
Re: List all Windows services 2
« Reply #7 on: June 02, 2022, 07:54:47 pm »
To experienced Freepascal people:
Sorry to ask such silly questions.
Please don't be.  IMO, that's the purpose of having this forum.  No one was born knowing everything.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

friend

  • Guest
Re: List all Windows services 2
« Reply #8 on: June 03, 2022, 07:27:21 am »
A mod just removed the autism surplus, that's unfortunate. :)
Please don't be.  IMO, that's the purpose of having this forum.  No one was born knowing everything.
Indeed, absolutely.
question

Units, you put them where they will be used. If you have a project where you want to use a unit, there it goes.  :)

jw

  • Full Member
  • ***
  • Posts: 126
list all Windows services.
« Reply #9 on: June 07, 2022, 05:28:22 pm »
@Friend: Bless you.  I knew someone knew where the code was hiding, and if I were more proficient, I'd have had a better chance of finding it and perhaps decoding the object.  Also, I have JwaWinSvc, but instead if adding the dependency, I decided to look through it and pull out the values I needed myself; as I like everything my code needs within itself if possible.  Also, when I did add JwaWinSvc, the library itself had more dependencies that I would have had to try and wring out of the hub, and that really bugged me.  I mean, it's not as if adding a download link to the code that I'm looking at would somehow make M$hub any less unscrupulous.   

@Remy Lebeau Yes, the principle of least permissions verses I really need to get something done and know what I'm doing except for that deliberately undocumented M$ bug.  Since this post is now available to the whole world, and I only asked for the permissions needed to list processes, yes less permissions; and thanks for the code to show the other nefarious states Windows services may find themselves in...

@PascalDragon ???  A friendly ROAR and dragon-ee, dragon, drag, drag fire burp.

@Jurassic Pork  Thank you Sir, you've been contributing to the community for a long time now.

@BobDog  Like Friend said:  I'd drop Jurassic Pork's utilwmi library directly into the directory of your source code.  Although, from the code you posted, it looks like you're shelling out to get it.  I first started off my code in that direction, and while I haven't yet taken a look at Jurassic Porks library, as you pointed out, that is probably what the library does.  The only comment I have about "Executing External Programs" which over the years has become very well documented, is, whenever possible, try to make TProcess and pipes work for you rather than a command that ends up being a Windows only API call.  Also, I decided that I should instead try to further the Free Pascal Communities knowledge about servicemanager, as the principle of least privilege dictates that it's far better not to shell out to an M$ buggy cmd prompt to run a buggy wmi command, when one can get close to the APi calls themselves via an open source Free Pascal service manger that's been part of the IDE for almost as long as

 

TinyPortal © 2005-2018