Solved

Use ChangeServiceConfigW from Visual Basic 6

Posted on 2004-03-20
5
902 Views
Last Modified: 2013-11-25
Okay, I'll award as many points as I am allowed for this one as long as the answer contains working code that uses the WIDE versions of the appropriate APIs.

I am having a very frustrating time using the ChangeServiceConfigW API function from Visual Basic 6.  All I want to do is change the "Start Type" of a service (e.g. from Automatic to Manual).  I am successfully calling the following API functions:

OpenSCManagerW()
LockServiceDatabase()
OpenServiceW()
QueryServiceConfigW()  <-  twice.  once to get the buffer size and once to retrieve the data

All of the above calls are in preparation for calling ChangeServiceConfigW().  The problem is that no matter how I call ChangeServiceConfigW(), I get a return value of &H0 and GetLastError() returns "Error 87: The parameter is incorrect."

Here is the Declare statement:

Private Declare Function ChangeServiceConfig Lib "advapi32.dll" Alias "ChangeServiceConfigW" ( _
    ByVal hService As Long, _
    ByVal dwServiceType As Long, _
    ByVal dwStartType As Long, _
    ByVal dwErrorControl As Long, _
    ByRef lpBinaryPathName As Any, _
    ByRef lpLoadOrderGroup As Any, _
    ByRef lpdwTagId As Long, _
    ByRef lpDependencies As Any, _
    ByRef lpServiceStartName As Any, _
    ByRef lpPassword As Any, _
    ByRef lpDisplayName As Any) As Long

I have tried the following:

lngReturnCode = ChangeServiceConfig(lngServiceHandle, SERVICE_NO_CHANGE, 4&, SERVICE_NO_CHANGE, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&)

** Note that the MSDN documentation incorrectly states that if you don't want to change the password or display name that you should pass SERVICE_NO_CHANGE, even though their C++ example correctly shows passing a NULL.

lngReturnCode = ChangeServiceConfig(lngServiceHandle, dwServiceType, dwStartType, dwErrorControl, lpBinaryPathName(0), lpLoadOrderGroup(0), lpdwTagId, lpDependencies(0), lpServiceStartName(0), bytPwd(0), lpDisplayName(0))

** where every parameter is filled with an identicle copy of the information returned from QueryServiceConfigW() (in the case of the arrays, they are byte arrays filled with Unicode strings and null terminators, except for lpDependencies(), which is double-null terminated).

I did find an interesting note at the following link:

http://www.tek-tips.com/gpviewthread.cfm/qid/608867/pid/711/lev2/4/lev3/32

This seemed to indicate that there was a known issue calling this API from VB, but their work around is what prompted me to try the second example above and it didn't help.  Also, it was the ANSI version, not the Unicode version.

Good Luck!

Tony
0
Comment
Question by:selke
  • 3
  • 2
5 Comments
 
LVL 2

Expert Comment

by:cfry001
ID: 10643270
Why do you want to use the wide versions?

I have got the ascii version working.
0
 
LVL 2

Expert Comment

by:cfry001
ID: 10643331
are you from a non-english speaking country?
0
 
LVL 2

Accepted Solution

by:
cfry001 earned 125 total points
ID: 10643426
here is some code that works for me with the wide versions:

Option Explicit



'All of the above calls are in preparation for calling ChangeServiceConfigW().  The problem is that no matter how I call ChangeServiceConfigW(), I get a return value of &H0 and GetLastError() returns "Error 87: The parameter is incorrect."

Private Declare Function ChangeServiceConfig Lib "advapi32.dll" Alias "ChangeServiceConfigW" ( _
    ByVal hService As Long, _
    ByVal dwServiceType As Long, _
    ByVal dwStartType As Long, _
    ByVal dwErrorControl As Long, _
    ByRef lpBinaryPathName As Any, _
    ByRef lpLoadOrderGroup As Any, _
    ByRef lpdwTagId As Long, _
    ByRef lpDependencies As Any, _
    ByRef lpServiceStartName As Any, _
    ByRef lpPassword As Any, _
    ByRef lpDisplayName As Any) As Long


'Private Declare Function OpenSCManager Lib "advapi32.dll" Alias "OpenSCManagerW" (ByVal lpMachineName As String, ByVal lpDatabaseName As String, ByVal dwDesiredAccess As Long) As Long
Private Declare Function OpenSCManager Lib "advapi32.dll" Alias "OpenSCManagerW" (ByVal lpMachineName As Long, ByVal lpDatabaseName As Long, ByVal dwDesiredAccess As Long) As Long
Private Declare Function LockServiceDatabase Lib "advapi32.dll" (ByVal hSCManager As Long) As Long
Private Declare Function OpenService Lib "advapi32.dll" Alias "OpenServiceW" (ByVal hSCManager As Long, ByVal lpServiceName As Long, ByVal dwDesiredAccess 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 GetLastError Lib "kernel32" () As Long


' Service Control Manager object specific access types
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const SC_MANAGER_CONNECT = &H1
Private Const SC_MANAGER_CREATE_SERVICE = &H2
Private Const SC_MANAGER_ENUMERATE_SERVICE = &H4
Private Const SC_MANAGER_LOCK = &H8
Private Const SC_MANAGER_QUERY_LOCK_STATUS = &H10
Private Const SC_MANAGER_MODIFY_BOOT_CONFIG = &H20

Private Const SERVICES_ACTIVE_DATABASE = "ServicesActive"
Private Const SERVICE_QUERY_CONFIG = &H1
Private Const SERVICE_CHANGE_CONFIG = &H2
Private Const SERVICE_QUERY_STATUS = &H4
Private Const SERVICE_ENUMERATE_DEPENDENTS = &H8
Private Const SERVICE_START = &H10
Private Const SERVICE_STOP = &H20
Private Const SERVICE_PAUSE_CONTINUE = &H40
Private Const SERVICE_INTERROGATE = &H80
Private Const SERVICE_USER_DEFINED_CONTROL = &H100
Private Const SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SC_MANAGER_CONNECT Or SC_MANAGER_CREATE_SERVICE Or SC_MANAGER_ENUMERATE_SERVICE Or SC_MANAGER_LOCK Or SC_MANAGER_QUERY_LOCK_STATUS Or SC_MANAGER_MODIFY_BOOT_CONFIG)
Private Const SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SERVICE_QUERY_CONFIG Or SERVICE_CHANGE_CONFIG Or SERVICE_QUERY_STATUS Or SERVICE_ENUMERATE_DEPENDENTS Or SERVICE_START Or SERVICE_STOP Or SERVICE_PAUSE_CONTINUE Or SERVICE_INTERROGATE Or SERVICE_USER_DEFINED_CONTROL)

Private Const SERVICE_DISABLED As Long = &H4
Private Const SERVICE_DEMAND_START As Long = &H3
Private Const SERVICE_AUTO_START As Long = &H2
Private Const SERVICE_SYSTEM_START As Long = &H1
Private Const SERVICE_BOOT_START As Long = &H0

'Service object specific access types

Private Const SERVICE_NO_CHANGE = &HFFFF


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


Sub ChangeServiceStartType(service As String, Auto As Boolean)
'OpenSCManagerW()
'LockServiceDatabase()
'OpenServiceW()
'QueryServiceConfigW()  <-  twice.  once to get the buffer size and once to retrieve the data
On Error GoTo errhandler
Dim lret As Long
Dim hSCManager As Long, hService As Long
Dim query As QUERY_SERVICE_CONFIG
Dim bufSize As Long, needed As Long
Dim MachineName As String, sDB As String, sServiceName As String
Dim lpMachineName As Long
Dim lpDB As Long
Dim lpService As Long
    MachineName = "XXXX" & Chr(0)
    sDB = SERVICES_ACTIVE_DATABASE & Chr(0)
    lpMachineName = StrPtr(MachineName)
    'service = service & Chr(0)
    lpDB = StrPtr(sDB)
    sServiceName = service & Chr(0)
    'sServiceName = StrConv(sServiceName, vbUnicode)
    lpService = StrPtr(sServiceName)
   
    hSCManager = OpenSCManager(lpMachineName, lpDB, SC_MANAGER_ALL_ACCESS)
    If hSCManager <> 0 Then
        hService = OpenService(hSCManager, lpService, SERVICE_ALL_ACCESS)
        If hService = 0 Then
            lret = GetLastError()
            Exit Sub
        End If


        lret = ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&)
        If lret = 0 Then
            lret = GetLastError()
            Exit Sub
        End If

    End If
    Exit Sub
errhandler:
    MsgBox Err.Number & " " & Err.Description
End Sub

Private Sub cmdStartType_Click()
    Call ChangeServiceStartType(txtServiceName, True)
End Sub
0
 

Author Comment

by:selke
ID: 10643698
I am using the wide versions because the code I am working on needs to be multi-lingual, including the asian dialects.

Your example worked perfectly, though you are using the samse Declare and call for ChangeServiceConfigW() as I am, so I have to go back and look at what else you may have done differently.  I was passing a NULL to MachineName and DatabaseName when I called OpenSCManagerW(), which worked fine for StartService() and QueryServiceStatusEx(), but perhaps it is causing me trouble here.

Anyway, you did exactly what I asked, so I'll be increasing the award to the maximum available and accepting your answer.

Thanks a million!

Tony
0
 

Author Comment

by:selke
ID: 10643875
Here's an FYI ...

AS far as I can tell, the only thing that IW as doing wrong was the following:

You declared the no change constant as:

Private Const SERVICE_NO_CHANGE = &HFFFF

I declared it as:

Private Const SERVICE_NO_CHANGE = &HFFFF&

Now, adding the trailing ampersand is something I habitually do because in the old days, VB was bad at resetting the high bits on a long integer if you only put a small value into it.  It turns out that for the first time in my memory, this practice bit me in the a$$.

Thank you for your help.

Tony
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now