Page 1 of 1
Get description of window service?
Posted: Thu Aug 09, 2007 11:07 pm
by Joakim Christiansen
Okay, so I'm enumerating the Windows Services available on the system and I get their description key from the registry which gives me data like this:
Code: Select all
@%SystemRoot%\system32\wcncsvc.dll,-4
@%SystemRoot%\system32\WcsPlugInService.dll,-201
@%systemroot%\system32\wdi.dll,-503
@%systemroot%\system32\wdi.dll,-501
@%systemroot%\system32\webclnt.dll,-101
@%SystemRoot%\system32\wecsvc.dll,-201
So how do I use these to get the actual description of the service?
Posted: Thu Aug 09, 2007 11:16 pm
by tinman
Why not use EnumServicesStatus_() which looks like it will give you a proper description (as well as a lot of other stuff)?
Posted: Fri Aug 10, 2007 1:02 am
by Joakim Christiansen
That is exactly what I do use to enumerate them, but it gives me no description of the service.
Neither does QueryServiceConfig_(), so that's kinda why I'm asking.
Posted: Fri Aug 10, 2007 12:14 pm
by tinman
Edit: I've removed the code because it was only listing the names not the descriptions. Doh.
Enumerate the services as you are doing now. Then for each one use OpenService to open it, then use QueryServiceConfig2_() (with info level 1) to get the description.
Posted: Fri Aug 10, 2007 12:19 pm
by Joakim Christiansen
I try to use QueryServiceConfig2 to see if I can get any description, but I have problems importing it and using it properly.

Posted: Fri Aug 10, 2007 12:42 pm
by SunSatION
Can't you list them from the registry?
Code: Select all
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services
To add a description to a new service, you need to write a reg entry, so i guess to read it, you need to read a registry entry
Posted: Fri Aug 10, 2007 12:44 pm
by tinman
Try this, seems to work for me. As for your original question about the DLL names and -numbers, you could try using LoadString_() to load the specified -(string number) from the DLL.
Code: Select all
#SERVICE_WIN32_OWN_PROCESS = $00000010
#SERVICE_WIN32_SHARE_PROCESS = $00000020
#SERVICE_WIN32 = #SERVICE_WIN32_OWN_PROCESS | #SERVICE_WIN32_SHARE_PROCESS
Structure SERVICE_DESCRIPTION
*lpDescription.c
EndStructure
Import "C:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\Advapi32.lib"
QueryServiceConfig2_.l(hService.l, dwInfoLevel.l, lpBuffer.l, cbBufSize.l, pcbBytesNeeded.l) As "_QueryServiceConfig2A@20"
EndImport
Define.l hSCM
Define.l dwError
Define.l success
service_data_size.l = 65536
Dim service_data.b(service_data_size)
Structure ptrENUM_SERVICE_STATUS
ess.ENUM_SERVICE_STATUS[0]
EndStructure
*service_info.ptrENUM_SERVICE_STATUS = @service_data(0)
Define.l dwBytesNeeded
Define.l dwNumberServices
dwResumeHandle.l = 0
description_data_size = 8192
Dim description_data.b(description_data_size)
*description.SERVICE_DESCRIPTION = @description_data(0)
hSCM.l = OpenSCManager_(0, 0, #GENERIC_READ)
If hSCM
Repeat
success.l = EnumServicesStatus_(hSCM, #SERVICE_WIN32, #SERVICE_ACTIVE, *service_info, service_data_size, @dwBytesNeeded, @dwNumberServices, @dwResumeHandle)
dwError.l = GetLastError_()
If success<>0 Or (success=0 And #ERROR_MORE_DATA = dwError)
For i.l = 0 To dwNumberServices-1
Debug PeekS(*service_info\ess[i]\lpDisplayName)
hService.l = OpenService_(hSCM, *service_info\ess[i]\lpServiceName, #GENERIC_READ)
If hService
success = QueryServiceConfig2_(hService, #SERVICE_CONFIG_DESCRIPTION, *description, description_data_size, @dwBytesNeeded)
;Debug Str(success)
If success
;Debug Str(*description)
If *description\lpDescription
Debug PeekS(*description\lpDescription)
Else
Debug "No description"
EndIf
Else
Debug Str(GetLastError_())
EndIf
CloseServiceHandle_(hService)
EndIf
Next
EndIf
Until #ERROR_MORE_DATA <> dwError
CloseServiceHandle_(hSCM)
EndIf
Posted: Fri Aug 10, 2007 2:07 pm
by tinman
You could try this for the @whatever strings. I can't test this, according to the MSDN localised strings only appeared in Vista which I don't have.
Code: Select all
service_description.s = "@%systemroot%\system32\webclnt.dll,-101"
If Left(service_description, 1)="@"
comma_pos.l = FindString(service_description, ",", 0)
service_desc_dll_name.s = Mid(service_description, 2, comma_pos - 2)
service_desc_str_id.l = Val(Mid(service_description, comma_pos+1, Len(service_description) - comma_pos))
full_path_length.l = ExpandEnvironmentStrings_(@service_desc_dll_name, 0, 0)
If full_path_length>0
full_path.s = Space(full_path_length)
If ExpandEnvironmentStrings_(@service_desc_dll_name, @full_path, full_path_length)
hModule = LoadLibrary_(full_path)
If hModule
description.s = Space(256)
Debug @description
string_length.l = LoadString_(hModule, -service_desc_str_id, @description, 256)
If string_length > 256
description.s = Space(string_length)
LoadString_(hModule, -service_desc_str_id, @description, string_length)
EndIf
If string_length > 0
Debug PeekS(@description)
EndIf
FreeLibrary_(hModule)
EndIf
EndIf
EndIf
EndIf
Posted: Sat Aug 11, 2007 12:04 am
by Joakim Christiansen
tinman wrote:Try this, seems to work for me.
I really appreciate your help, but sadly this code gives me a fatal error :S
I tried with PB 4.02 and both the latest beta versions, but I'm using Vista, maybe that's it.
And the code right over this post works very fine!

But I want support for XP too so can't use it I guess, or maybe (I'll try on XP later).
Posted: Sat Aug 11, 2007 5:58 am
by Joakim Christiansen

Anyone know why this happens?
Posted: Sat Aug 11, 2007 5:11 pm
by Hi-Toro
Here's the Registry method... for NT-based Windows only (tested only on XP):
Code: Select all
; -----------------------------------------------------------------------------
; TURN DEBUGGER ON TO SEE THE OUTPUT!!!
; -----------------------------------------------------------------------------
; Just call GetServiceList () and then iterate through the list (see
; demo at bottom of source)...
; -----------------------------------------------------------------------------
; Required list...
; -----------------------------------------------------------------------------
Structure ServiceList
displayname.s
description.s
EndStructure
Global NewList ServiceList.ServiceList ()
; -----------------------------------------------------------------------------
; Registry support functions...
; -----------------------------------------------------------------------------
Procedure OpenKey (openkey, subkey$, flags)
result = RegOpenKeyEx_ (openkey, subkey$, 0, flags, @handle)
If result = #ERROR_SUCCESS
ProcedureReturn handle
EndIf
EndProcedure
Procedure CloseKey (openkey)
ProcedureReturn RegCloseKey_ (openkey)
EndProcedure
Procedure.s GetStringValue (openkey, value$)
buffer$ = Space (1024)
size.l = 1024
res = RegQueryValueEx_ (openkey, @value$, #Null, @type, @buffer$, @size)
If res <> #ERROR_SUCCESS
buffer$ = ""
EndIf
ProcedureReturn buffer$
EndProcedure
Procedure GetIntValue (openkey, value$)
size = 4
RegQueryValueEx_ (openkey, @value$, #Null, @type, @res, @size)
ProcedureReturn res
EndProcedure
; -----------------------------------------------------------------------------
; Specific to listing services...
; -----------------------------------------------------------------------------
Procedure EnumServices (openkey)
buffsize = 256
buffer$ = Space (buffsize)
result = RegEnumKeyEx_ (openkey, index, @buffer$, @buffsize, #Null, #Null, #Null, @written.SYSTEMTIME)
index = index + 1
If result = #ERROR_SUCCESS
Repeat
buffsize = 256
buffer$ = Space (buffsize)
result = RegEnumKeyEx_ (openkey, index, @buffer$, @buffsize, #Null, #Null, #Null, @written.SYSTEMTIME)
If result = #ERROR_SUCCESS
key = OpenKey (openkey, buffer$, #KEY_ALL_ACCESS)
If key
servicetype = GetIntValue (key, "Type")
; Retrieve only those listed in Control Panel -> Admin Tools -> Services...
If servicetype > 8 ; See http://www.jsifaq.com/SF/Tips/Tip.aspx?id=0324
AddElement (ServiceList ())
dsp$ = GetStringValue (key, "DisplayName")
dsc$ = GetStringValue (key, "Description")
If dsp$ = ""
dsp$ = "Unknown service"
EndIf
If dsc$ = ""
dsc$ = "[No description]"
EndIf
ServiceList ()\displayname = dsp$
ServiceList ()\description = dsc$
EndIf
CloseKey (key)
EndIf
EndIf
index = index + 1
Until result = #ERROR_NO_MORE_ITEMS
EndIf
EndProcedure
; -----------------------------------------------------------------------------
; Easy wrapper function...
; -----------------------------------------------------------------------------
Procedure GetServiceList ()
ClearList (ServiceList ())
services = OpenKey (#HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Services", #KEY_ALL_ACCESS)
If services
EnumServices (services)
CloseKey (services)
EndIf
ResetList (ServiceList ())
EndProcedure
; -----------------------------------------------------------------------------
; D E M O . . .
; -----------------------------------------------------------------------------
GetServiceList ()
While NextElement (ServiceList ())
Debug ServiceList ()\displayname
Debug Chr (34) + ServiceList ()\description + Chr (34)
Debug ""
Wend
Posted: Sat Aug 11, 2007 5:53 pm
by tinman
Joakim Christiansen wrote:tinman wrote:Try this, seems to work for me.
I really appreciate your help, but sadly this code gives me a fatal error :S
I tried with PB 4.02 and both the latest beta versions, but I'm using Vista, maybe that's it.
There are quite a few places in the code where pointer values are not checked. Perhaps if your config has no description or display name then the pointers will be NULL and my code doesn't catch that.
And the code right over this post works very fine! :D
But I want support for XP too so can't use it I guess, or maybe (I'll try on XP later).
If you can get the original code working (that enumerates and gets the description) then you can use that on XP. If you also add the code that checks for "@" at the start of the description then it should work for XP and Vista.
For the linker error check the following:
- Path to .lib file is correct in the import statement - I hardcoded it to the default English language location for the Vista platform SDK. As you said before, the PB libs do not come with that function included.
- Try using "_QueryServiceConfig2A@20" in the import line if that doesn't work
- Try changing it to _QueryServiceConfig2W if you are using Unicode.
- I had another thing to try but I forgot.