Link to home
Start Free TrialLog in
Avatar of jilamints
jilamints

asked on

Handling Windows Services

Hi All:

Allow me to be very specific here, I'm trying to get something that will specifically tell me if the Messenger service is "Automatically" started ? Then, all the user to to disable this. And secondly, just tell the user if it is running at the moment and of course give them the option to start and stop it...

Im not talking about MSN Messenger, Im talking about the net send version - I want something I can distribute to my networked machines and friends or clients - Instead of making them do it the old fashion way !!

Thanks in advance !
Avatar of TimCottee
TimCottee
Flag of United Kingdom of Great Britain and Northern Ireland image

Hi jilamints,

http://www.timcottee.tk has a sample application that can manipulate services. It will cover the second part of your request (being able to stop and start). Will have a look into the automatic start/disable stuff shortly.

Tim Cottee MCSD, MCDBA, CPIM
Brainbench MVP for Visual Basic
http://www.brainbench.com

Experts-Exchange Advisory Board Member
Avatar of crescendo
crescendo

Hi,

I have two ideas. First, you can use NETSVC.EXE (part of the Windows 2000 Resource Kit) to query, stop and start services. It's a command line tool, so you could write a simple batch file to control it. It will start/stop the service on remote machines too, which may be useful in the context you describe.

Second, there are APIs to control services. The code below is from http://www.allapi.net/, a site that describes lots of APIs and gives example of how to use them. The main API is EnumServicesStatus but as you can see from the code below, there are others you will need too.

Regards

Crescendo


Const ERROR_MORE_DATA = 234
Const SERVICE_ACTIVE = &H1
Const SERVICE_INACTIVE = &H2
Const SC_MANAGER_ENUMERATE_SERVICE = &H4
Const SERVICE_WIN32_OWN_PROCESS As Long = &H10
Const SERVICE_WIN32_SHARE_PROCESS As Long = &H20
Const SERVICE_WIN32 As Long = SERVICE_WIN32_OWN_PROCESS + SERVICE_WIN32_SHARE_PROCESS
Private Type SERVICE_STATUS
    dwServiceType As Long
    dwCurrentState As Long
    dwControlsAccepted As Long
    dwWin32ExitCode As Long
    dwServiceSpecificExitCode As Long
    dwCheckPoint As Long
    dwWaitHint As Long
End Type
Private Type ENUM_SERVICE_STATUS
    lpServiceName As Long
    lpDisplayName As Long
    ServiceStatus As SERVICE_STATUS
End Type
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 EnumServicesStatus Lib "advapi32.dll" Alias "EnumServicesStatusA" (ByVal hSCManager As Long, ByVal dwServiceType As Long, ByVal dwServiceState As Long, lpServices As Any, ByVal cbBufSize As Long, pcbBytesNeeded As Long, lpServicesReturned As Long, lpResumeHandle As Long) As Long
Private Declare Function CloseServiceHandle Lib "advapi32.dll" (ByVal hSCObject As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyA" (szDest As String, szcSource As Long) As Long
Private Sub Form_Load()
    'KPD-Team 2000
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    Dim hSCM As Long, lpEnumServiceStatus() As ENUM_SERVICE_STATUS, lngServiceStatusInfoBuffer As Long
    Dim strServiceName As String * 250, lngBytesNeeded As Long, lngServicesReturned As Long
    Dim hNextUnreadEntry As Long, lngStructsNeeded As Long, lngResult As Long, i As Long
    'Open connection to Service Control Manager.
    hSCM = OpenSCManager(vbNullString, vbNullString, SC_MANAGER_ENUMERATE_SERVICE)
    If hSCM = 0 Then
        MsgBox "OpenSCManager failed. LastDllError = " & CStr(Err.LastDllError)
        Exit Sub
    End If
    'Get buffer size (bytes) without passing a buffer
    'and make sure starts at 0th entry.
    hNextUnreadEntry = 0
    lngResult = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_ACTIVE Or SERVICE_INACTIVE, ByVal &H0, &H0, lngBytesNeeded, lngServicesReturned, hNextUnreadEntry)
    'We should receive MORE_DATA error.
    If Not Err.LastDllError = ERROR_MORE_DATA Then
        MsgBox "LastDLLError = " & CStr(Err.LastDllError)
        Exit Sub
    End If
    'Calculate the number of structures needed.
    lngStructsNeeded = lngBytesNeeded / Len(lpEnumServiceStatus(0)) + 1
    'Redimension the array according to our calculation.
    ReDim lpEnumServiceStatus(lngStructsNeeded - 1)
    'Get buffer size in bytes.
    lngServiceStatusInfoBuffer = lngStructsNeeded * Len(lpEnumServiceStatus(0))
    'Get services information starting entry 0.
    hNextUnreadEntry = 0
    lngResult = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_ACTIVE Or SERVICE_INACTIVE, lpEnumServiceStatus(0), lngServiceStatusInfoBuffer, lngBytesNeeded, lngServicesReturned, hNextUnreadEntry)
    If lngResult = 0 Then
        MsgBox "EnumServicesStatus failed. LastDllError = " & CStr(Err.LastDllError)
        Exit Sub
    End If
    'Get the strings and display them.
    Me.AutoRedraw = True
    Me.Print "All registered services:" + vbCrLf
    For i = 0 To lngServicesReturned - 1
        lngResult = lstrcpy(ByVal strServiceName, ByVal lpEnumServiceStatus(i).lpServiceName)
        Me.Print StripTerminator(strServiceName) + " - ";
        lngResult = lstrcpy(ByVal strServiceName, ByVal lpEnumServiceStatus(i).lpDisplayName)
        Me.Print StripTerminator(strServiceName)
    Next i
    'Clean up.
    CloseServiceHandle (hSCM)
End Sub
Function StripTerminator(sInput As String) As String
    Dim ZeroPos As Integer
    ZeroPos = InStr(1, sInput, Chr$(0))
    If ZeroPos > 0 Then
        StripTerminator = Left$(sInput, ZeroPos - 1)
    Else
        StripTerminator = sInput
    End If
End Function
Avatar of jilamints

ASKER

TimCottee: Thanks for that, that is really fantastic stuff ! I'm of course no expert with VB, but that was easy enough to get my head around after a little thing - I'm sure I can now use this within my own code... If you could look into that issue of the Autostart, that would be great...

The same deal again - Want to be able to test its state, and of course enable or disable it...

Now correct me if I'm wrong here (because I had to get the computers name via the API) I could really now get a list of computer names within the workgroup, or domain, and then do the same thing ?

Check service status etc ? Correct ? Just wondering...
I would also like to say, I will be increasing the points to provide crescendo with his fair share... I would like to offer you 250 points for your efforts if you think that is fair... As for TimCottee, I will still give you the 500 points, but would like to offer more if you can complete my question in full... :-)


Thanks again guys ! GREAT HELP !
Sorry for the number of posts, but I have just tested this on Windows 2000 & XP - Both work fine... NT I can't test it on but on Windows 2000 Adv. Server, it says the service is not found ? How can that be ? It is exactly the same ?
Hi jilamints

Thanks for the offer of points. Did you try using netsvc.exe? It's really easy to use to start and stop services, and find out if they are running. For example, you could create a batch file that sends it output to a text file, and the text file is easy to parse. The responses you get from netsvc.exe are simply:

Service is running on \\ComputerName
Service is stopped on \\ComputerName
Service is pending start on \\ComputerName
Service is pending stop on \\ComputerName

So a batch file like below would do the trick:

@ECHO OFF
NETSVC.EXE %1 %2 %3 > C:\MyDir\Results.txt

Where %1 is the service name ("Messenger" in your case)
           %2 is the computer name
           %3 is the action, /query, /stop, /start

You shell this in VB, then open the text file C:\MyDir\Results.txt and see if it says "Service is running" etc. and take action accordingly. That does everything you asked for, and is easy to code.

crescendo
I have seen it done like this before but was trying to consider my long term options such as allowing the application to work over a network. In such an event I thought that *maybe* using something like Tims answers might be just a touch bit better ? Not sure but I do like to keep my options open !

Kind Regards
But netsvc.exe DOES work over a network, which is why I suggested it.
ASKER CERTIFIED SOLUTION
Avatar of DominicCronin
DominicCronin
Flag of Netherlands image

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
TimCottee: Any Luck ?
Indeed, I remembered how you can do this. It is actually governed by registry entries:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rpcnet\Start = 2

For example is Automatic.

The values for this key are:

START TYPE     LOADER     MEANING

0x0            Kernel     Represents a part of the
(Boot)                    driver stack for the boot
                          (startup) volume and must
                          therefore be loaded by the
                          Boot Loader.

0x1            I/O        Represents a driver to be loaded
(System)       subsystem  at Kernel initialization.

0x2            Service    To be loaded or started
(Auto load)    Control    automatically for all startups,
               Manager    regardless of service type.

0x3            Service    Available, regardless of type,
(Load on       Control    but will not be started until
demand)        Manager    the user starts it (for example,
                          by using the Devices icon in
                          Control Panel).

0x4            Service    NOT TO BE STARTED UNDER ANY
(disabled)     Control    CONDITIONS.
               Manager


For more info see http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q103/0/00.asp&NoWebContent=1
By the way, the wbem scripting approach works over a network too - assuming that you have the correct privileges.
DominicCronin: Your answer sounds like its the pick of the bunch here... However could you just clear up one thing... What privileges would be required to use this over a network ? See I wouldn't mind (although Im not sure how) listing in a treeview or whatever, a list of networked computers and being able to try and apply this code to those machines...

But if it could detect if it had access, that would be great... I know Im kinda going beyond my orginal question but yeah... Any help would be great...


PS: Any other reason why this would NOT work on a Windows 2000 or XP machine that I need to know about...

Also to everyone else... At this stage I do prefer DominicCronin answer and will give him full points... With that said, I also feel crescendo should get a little something too as should you Tim ? If you want to add to this, let me know - Will arrange a new blank question and give out the points as you all see fit...

Kind Regards,

Jilamints
Providing you have administrator privileges on the domain and these have not been explicitly modified or denied on any of the machines that are part of the domain then Dominic's approach will work on any NT based system from NT3.51 up. There are some applications which do this specifically, VNCCon for example is a great tool that allows you to manage VNC installations and services across multiple domains in fact always with the proviso that you have the correct administrative privileges.
jil - I'm also happy with a split or something - there's plenty of good effort gone in here.

At Tim says - basically you need to have sufficient privileges that you could do the action if you were the interactive user. Check out MSDN for details of extra things you can specify to control security. Any recent version of Windows supports this.
I have been of course playing around with all this and found that using Dominics method can *sometimes* when you go to start the service, fail to do so - For that reason, I think I might use Tims answer for that side of things and Doms for the Auto start part which seems to work perfectly (not an error in the code btw...)

Would anyone think this could cause problems down the track ?


Tim: I will set up a new question to provide points to yourself - Will then prepare to close this off in the next few days...

Once again, many thanks to all ! I think my next question will be a networking one hahahaha ! Thanks again guys !

Regards,

Jilamints
When you start a service using a wbem script, the function returns a code indicating either 0 for success or various error codes.