Link to home
Start Free TrialLog in
Avatar of Jedi
Jedi

asked on

Getting Information about a WIN NT Service from VB ?

Hi !
Has anyone succceeded with retrieving Service Information
using : the API call QueryServiceConfig from VB.
In that case I want to know how !

Like this:
The API requires a pointer to a structure, containing both numeric and string data.  This I have made with API text viewer. Nothing strange with this!

But, the result in the stucture after a successfull call is a mess within the strings. The Numerics works fine, but the separate strings are all placed in the first string and this one starts with a lot of strange caracters in the beginning !

Anyone ?
Avatar of clifABB
clifABB

Can you post your code?
What service are you trying to get information on?
Avatar of Jedi

ASKER

I'm trying to get information about a lot of services, in fact
every registered service

Avatar of Jedi

ASKER

Ok som e code I'm using:
It's a lot of code to post if it's going to compile, the API calls and error handeling and the declarations takes a lot of space.

I'm mostly interested in code that will retrieve cdata using the:
QueryServiceConfig call:
If there is some need for initializing my VB strings before the call or something.
Some code :
'Declarations:
'-------------
Public Declare Function QueryServiceConfig Lib "advapi32.dll" Alias "QueryServiceConfigA" (ByVal hService As Long, lpServiceConfig As QUERY_SERVICE_CONFIG, ByVal cbBufSize As Long, pcbBytesNeeded As Long) As Long

Type QUERY_SERVICE_CONFIG
        dwServiceType As Long
        dwStartType As Long
        dwErrorControl As Long
        lpBinaryPathName As String '* 255
        lpLoadOrderGroup As String '* 255
        dwTagId As Long
        lpDependencies As String '* 255
        lpServiceStartName As String '* 255
        lpDisplayName As String '* 255
End Type

'---------------------------

'Running
'---------------------------
Dim lresult As Long
Dim pcbBytesNeeded As Long
Dim lpServiceConfig As QUERY_SERVICE_CONFIG
Dim cbBufSize As Long

lpServiceConfig.dwServiceType = 0
lpServiceConfig.dwStartType = 0
lpServiceConfig.dwErrorControl=0
lpServiceConfig.lpBinaryPathName = String(255, vbNullChar)lpServiceConfig.lpLoadOrderGroup = String(255, vbNullChar)lpServiceConfig.dwTagId = 0
lpServiceConfig.lpDependencies = String(255, vbNullChar)lpServiceConfig.lpServiceStartName = String(255, vbNullChar)  lpServiceConfig.lpDisplayName = String(255, vbNullChar)      


cbBufSize = LenB(lpServiceConfig)


'Stop Service it first
'    SvcsStop (lpServiceName)
   
    'Open the DB
'    hSCManager = SvcsOpenDB("")
   
'    If hSCManager = Null Then
'        SvcsDisable = False
'        Exit Function
'        Exit Sub
'    End If
       
    'Open the service in question
'    hService = SvcsOpen(hSCManager, lpServiceName)
   
    'Get the right values
lresult = QueryServiceConfig(hService, lpServiceConfig, cbBufSize, pcbBytesNeeded)

'****The strings within the lpServiceConfig structure are a mess.

Hope it gives some clues

The problem arises when you try to access null-terminated strings through pointers embedded in a structure.  In order to do this properly, you need to retrieve the string pointers as integer values (define them as "Long" in your VB type, not "String") and then convert them into VB strings.

The following code is a sample of how to do this.  The C++ code is for a DLL which will convert a pointer stored as an integer value into a VB string, and the VB application is a simple demonstration of how to use the library.

==================================
GetBSTR.cpp
==================================
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#pragma warning( disable : 4201 )
#include <windows.h>
#include <ole2.h>


char const * const gc_p = "TestString";


/*
 *  test function for returning a pointer to a string as a long
 *  integer value...
 */
extern "C" long __declspec( dllexport ) __stdcall GetString( )
    {
    return long( gc_p );
    }


/*
 *  take the given string pointer and convert it to a Visual Basic
 *  string...
 */
extern "C" BSTR __declspec( dllexport ) __stdcall GetStringFromPointer( char const * const p )
    {
    return ::SysAllocStringByteLen( p
                                  , ::strlen( p )
                                  );
    }



==================================
VB Sample Program
==================================
Option Explicit
Declare Function GetString Lib "GetBSTR.dll" Alias "_GetString@0" () As Long
Declare Function GetStringFromPointer Lib "GetBSTR.dll" Alias "_GetStringFromPointer@4" (ByVal l As Long) As String


Sub main()

Dim l As Long
l = GetString()

Dim s As String
s = GetStringFromPointer(l)

End Sub

Jedi,

The main problem here is the size of QUERY_SERVICE_CONFIG is not enough for the API function QueryServiceConfig to retrieve the service information, so you must allocate enough space for QUERY_SERVICE_CONFIG structure before calling QueryServiceConfig.
The following steps must be done:
1- Change the variables with string data type in QUERY_SERVICE_CONFIG type to Long data type.
2- Declare a variable as an array with 10 dimensions of this type and pass it to QueryServiceConfig function with the size (10 * length of the first dimension of variable).
3- To get the string use lstrcpy and lstrlen API functions (you don't have to write a C code to do that).

The following example illustrates how to get the information for Schadule service:

Example
=======
Private Type QUERY_SERVICE_CONFIG
 dwServiceType As Long
 dwStartType As Long
 dwErrorControl As Long
 lpBinaryPathName As Long
 lpLoadOrderGroup As Long
 dwTagId As Long
 lpDependencies As Long
 lpServiceStartName As Long
 lpDisplayName As Long
End Type

Private Const GENERIC_READ = &H80000000
Private Const SERVICE_QUERY_CONFIG = &H1

Private Declare Function OpenSCManager Lib "advapi32.dll" Alias "OpenSCManagerA" _
    (ByVal lpMachineName As String, ByVal lpDatabaseName As String, _
    ByVal dwDesiredAccess As Long) As Long
Private Declare Function OpenService Lib "advapi32.dll" Alias "OpenServiceA" (ByVal hSCManager As Long, ByVal lpServiceName As String, ByVal dwDesiredAccess As Long) As Long
Private Declare Function CloseServiceHandle Lib "advapi32.dll" (ByVal hSCObject As Long) As Long
Private Declare Function QueryServiceConfig Lib "advapi32.dll" Alias "QueryServiceConfigA" (ByVal hService As Long, lpServiceConfig As QUERY_SERVICE_CONFIG, ByVal cbBufSize As Long, pcbBytesNeeded As Long) As Long
Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As Long) As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long

Private Sub Command1_Click()
 Dim hSCM As Long
 Dim hService As Long
 Dim sMachineName As String
 Dim sDatabaseName As String
 Dim lResult As Long
 Dim pcbBytesNeeded As Long
 Dim lpServiceConfig() As QUERY_SERVICE_CONFIG
 Dim sBinaryPathName As String
 Dim sLoadOrderGroup As String
 Dim sDependencies As String
 Dim sServiceStartName As String
 Dim sDisplayName As String
 
 hSCM = OpenSCManager(sMachineName, sDatabaseName, GENERIC_READ)
 hService = OpenService(hSCM, "Schedule", SERVICE_QUERY_CONFIG)
 
 ReDim lpServiceConfig(100) As QUERY_SERVICE_CONFIG
 lResult = QueryServiceConfig(hService, lpServiceConfig(0), 100 * Len(lpServiceConfig(0)), pcbBytesNeeded)
 
 sBinaryPathName = Space(255)
 lResult = lstrcpy(sBinaryPathName, lpServiceConfig(0).lpBinaryPathName)
 sBinaryPathName = Mid(sBinaryPathName, 1, lstrlen(sBinaryPathName))
 
 sLoadOrderGroup = Space(255)
 lResult = lstrcpy(sLoadOrderGroup, lpServiceConfig(0).lpLoadOrderGroup)
 sLoadOrderGroup = Mid(sLoadOrderGroup, 1, lstrlen(sLoadOrderGroup))
 
 sDependencies = Space(255)
 lResult = lstrcpy(sDependencies, lpServiceConfig(0).lpDependencies)
 sDependencies = Mid(sDependencies, 1, lstrlen(sDependencies))
 
 sServiceStartName = Space(255)
 lResult = lstrcpy(sServiceStartName, lpServiceConfig(0).lpServiceStartName)
 sServiceStartName = Mid(sServiceStartName, 1, lstrlen(sServiceStartName))
 
 sDisplayName = Space(255)
 lResult = lstrcpy(sDisplayName, lpServiceConfig(0).lpDisplayName)
 sDisplayName = Mid(sDisplayName, 1, lstrlen(sDisplayName))
 
 MsgBox "Service Type: " & lpServiceConfig(0).dwServiceType & vbCrLf & _
        "Start Type: " & lpServiceConfig(0).dwStartType & vbCrLf & _
        "Error Control: " & lpServiceConfig(0).dwErrorControl & vbCrLf & _
        "Binary Path Name: " & sBinaryPathName & vbCrLf & _
        "Load Order Group: " & sLoadOrderGroup & vbCrLf & _
        "Tag ID: " & lpServiceConfig(0).dwTagId & vbCrLf & _
        "Dependencies: " & sDependencies & vbCrLf & _
        "Service Start Name: " & sServiceStartName & vbCrLf & _
        "Display Name: " & sDisplayName
 
 Call CloseServiceHandle(hService)
 Call CloseServiceHandle(hSCM)
End Sub


Best regards
Bin Huwairib
Avatar of Jedi

ASKER

Thanks Mwalsh, but the commented answer from Bin is even better.

Exelent answer from Bin Huwairib ,if you post a answer I'll give you the points !
//Jedi

ASKER CERTIFIED SOLUTION
Avatar of bin_huwairib
bin_huwairib

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Jedi

ASKER

Excellent , That was the kind of answerI was looking for,
An explanation and a solution.
Thanks again

//Jedi