
I left the code as I tested it, so you can changed (or improve it) as you wish.
The only thing untested is the ErrorHandling procedure. Couldn't find a way to produce a failure in the API functions Calls.
Another Piece of code related with services, is the creation/remove/start/stop a service from an external application (a setup App?). On this one I changed the constant names to not conflict with some allready existent libs. But you can change them back. Also commented out the constants not used, so if you want can remove them to make the code smaller
I hope This will help some one
The service
Code: Select all
; Apr. 12, 2003
; Converted to PB by Richard Eikeland
; Jan. 3, 2009
; Changed by Virginio Reis (reisve)
; This code is posted as is with out any waranties.
;
#SERVICE_WIN32_OWN_PROCESS = $10
#SERVICE_WIN32_SHARE_PROCESS = $20
#SERVICE_WIN32 = #SERVICE_WIN32_OWN_PROCESS + #SERVICE_WIN32_SHARE_PROCESS
#SERVICE_ACCEPT_STOP = $1
#SERVICE_ACCEPT_PAUSE_CONTINUE = $2
#SERVICE_ACCEPT_SHUTDOWN = $4
#SC_MANAGER_CONNECT = $1
#SC_MANAGER_CREATE_SERVICE = $2
#SC_MANAGER_ENUMERATE_SERVICE = $4
#SC_MANAGER_LOCK = $8
#SC_MANAGER_QUERY_LOCK_STATUS = $10
#SC_MANAGER_MODIFY_BOOT_CONFIG = $20
#STANDARD_RIGHTS_REQUIRED = $F0000
#SERVICE_QUERY_CONFIG = $1
#SERVICE_CHANGE_CONFIG = $2
#SERVICE_QUERY_STATUS = $4
#SERVICE_ENUMERATE_DEPENDENTS = $8
#SERVICE_START = $10
#SERVICE_STOP = $20
#SERVICE_PAUSE_CONTINUE = $40
#SERVICE_INTERROGATE = $80
#SERVICE_USER_DEFINED_CONTROL = $100
#SERVICE_ALL_ACCESS = #STANDARD_RIGHTS_REQUIRED | #SERVICE_QUERY_CONFIG | #SERVICE_CHANGE_CONFIG | #SERVICE_QUERY_STATUS | #SERVICE_ENUMERATE_DEPENDENTS | #SERVICE_START | #SERVICE_STOP | #SERVICE_PAUSE_CONTINUE | #SERVICE_INTERROGATE |#SERVICE_USER_DEFINED_CONTROL
#SERVICE_DEMAND_START = $3
#SERVICE_ERROR_NORMAL = $1
;- SERVICE_CONTROL
#SERVICE_CONTROL_STOP = $1
#SERVICE_CONTROL_PAUSE = $2
#SERVICE_CONTROL_CONTINUE = $3
#SERVICE_CONTROL_INTERROGATE = $4
#SERVICE_CONTROL_SHUTDOWN = $5
;-SERVICE_STATE
#SERVICE_STOPPED = $1
#SERVICE_START_PENDING = $2
#SERVICE_STOP_PENDING = $3
#SERVICE_RUNNING = $4
#SERVICE_CONTINUE_PENDING = $5
#SERVICE_PAUSE_PENDING = $6
#SERVICE_PAUSED = $7
Global ServiceStatus.SERVICE_STATUS
Global hServiceStatus.l
Global SERVICE_NAME.s
Global Finish.l
Global sThread.l
Global rThread.l
Global UserFunction
Global NotifyFunction
Declare Handler(fdwControl.l)
Declare ServiceMain(dwArgc.l, lpszArgv.l)
Procedure ServiceFunction()
OpenFile(0, "c:\MyTestSvc.txt")
FileSeek (0, Lof(0) )
WriteStringN(0, "Service Function is Running")
CloseFile(0)
EndProcedure
Procedure ServiceNotify(Parameter)
OpenFile(0, "c:\MyTestSvc.txt")
FileSeek (0, Lof(0) )
WriteStringN(0, "Service Status - " + Str(Parameter))
CloseFile(0)
EndProcedure
Procedure ErrorHandler()
Result = GetLastError_()
OpenFile(0, "c:\MyTestSvc.txt")
FileSeek (0, Lof(0) )
WriteStringN(0, "Error Ocurred - " + Str(Result))
CloseFile(0)
Finish = 1
ServiceStatus\dwCurrentState = #SERVICE_STOP_PENDING
SetServiceStatus_(hServiceStatus, ServiceStatus)
ServiceStatus\dwCurrentState = #SERVICE_STOPPED
SetServiceStatus_(hServiceStatus, ServiceStatus)
EndProcedure
Procedure RunService(svcName.s, usrFunction, nfyFunction)
hSCManager.l
hService.l
ServiceTableEntry.SERVICE_TABLE_ENTRY
b.l
cmd.s
SERVICE_NAME = svcName
UserFunction = usrFunction
NotifyFunction = nfyFunction
*sname.s = SERVICE_NAME
ServiceTableEntry\lpServiceName = @SERVICE_NAME
ServiceTableEntry\lpServiceProc = @ServiceMain()
b = StartServiceCtrlDispatcher_(@ServiceTableEntry)
If b = 0 : ErrorHandler() : EndIf
Repeat : Until Finish =1 : End
EndProcedure
Procedure Handler(fdwControl.l)
b.l
id.l
Select fdwControl
Case #SERVICE_CONTROL_PAUSE
ServiceStatus\dwCurrentState = #SERVICE_PAUSED
Case #SERVICE_CONTROL_CONTINUE
ServiceStatus\dwCurrentState = #SERVICE_RUNNING
Case #SERVICE_CONTROL_STOP
ServiceStatus\dwWin32ExitCode = 0
ServiceStatus\dwCurrentState = #SERVICE_STOP_PENDING
ServiceStatus\dwCheckPoint = 0
ServiceStatus\dwWaitHint = 0
b = SetServiceStatus_(hServiceStatus, ServiceStatus)
If b = 0 : ErrorHandler() : EndIf
Finish = 1
ServiceStatus\dwCurrentState = #SERVICE_STOPPED
Case #SERVICE_CONTROL_INTERROGATE
EndSelect
sThread = CreateThread_(0, 0, NotifyFunction, ServiceStatus\dwCurrentState, 0, @id )
If sThread = #Null : ErrorHandler() : EndIf
WaitThread(sThread)
b = SetServiceStatus_(hServiceStatus, ServiceStatus)
If b = 0: ErrorHandler() : EndIf
EndProcedure
Procedure ServiceMain(dwArgc.l, lpszArgv.l)
b.l
id.l
ServiceStatus\dwServiceType = #SERVICE_WIN32_OWN_PROCESS
ServiceStatus\dwCurrentState = #SERVICE_START_PENDING
ServiceStatus\dwControlsAccepted = #SERVICE_ACCEPT_STOP | #SERVICE_ACCEPT_PAUSE_CONTINUE | #SERVICE_ACCEPT_SHUTDOWN
ServiceStatus\dwWin32ExitCode = 0
ServiceStatus\dwServiceSpecificExitCode = 0
ServiceStatus\dwCheckPoint = 0
ServiceStatus\dwWaitHint = 0
hServiceStatus = RegisterServiceCtrlHandler_(SERVICE_NAME, @Handler())
ServiceStatus\dwCurrentState = #SERVICE_START_PENDING
b = SetServiceStatus_(hServiceStatus, ServiceStatus)
If b = 0 : ErrorHandler() : EndIf
hThread = CreateThread_(0, 0, UserFunction, 0, 0, @id)
If hThread = #Null : ErrorHandler() : EndIf
ServiceStatus\dwCurrentState = #SERVICE_RUNNING
rThread = CreateThread_(0, 0, NotifyFunction, ServiceStatus\dwCurrentState, 0, @id)
If rThread = #Null : ErrorHandler() : EndIf
WaitThread(rThread)
b = SetServiceStatus_(hServiceStatus, ServiceStatus)
If b = 0 : ErrorHandler() : EndIf
EndProcedure
RunService("MyTestSvc", @ServiceFunction(), @ServiceNotify())
Code: Select all
; ** Access Rights for SCM
#SCM_ALL_ACCESS = $F003F ;Includes STANDARD_RIGHTS_REQUIRED, in addition To all access rights in this table.
;#SCM_CREATE_SERVICE = $0002 ;Required To call the CreateService function To create a service object And add it To the database.
;#SCM_CONNECT = $0001 ;Required To connect To the service Control manager.
;#SCM_ENUMERATE_SERVICE = $0004 ;Required To call the EnumServicesStatusEx function To list the services that are in the database.
;#SCM_LOCK = $0008 ;Required To call the LockServiceDatabase function To acquire a lock on the database.
;#SCM_MODIFY_BOOT_CONFIG = $0020 ;Required To call the NotifyBootConfigStatus function.
;#SCM_QUERY_LOCK_STATUS = $0010
; ** Access Rights for Services
#SVC_ALL_ACCESS = $F01FF ; Includes STANDARD_RIGHTS_REQUIRED in addition To all access rights in This table.
;#SVC_CHANGE_CONFIG = $0002 ; Required To call The ChangeServiceConfig Or ChangeServiceConfig2 function To change The service configuration. Because This grants The caller The right To change The executable file that The system runs, it should be granted only To administrators.
;#SVC_ENUMERATE_DEPENDENTS = $0008 ; Required To call The EnumDependentServices function To enumerate all The services dependent on The service.
;#SVC_INTERROGATE = $0080 ; Required To call The ControlService function To ask The service To report its Status immediately.
;#SVC_PAUSE_CONTINUE = $0040 ; Required To call The ControlService function To pause Or Continue The service.
;#SVC_QUERY_CONFIG = $0001 ; Required To call The QueryServiceConfig And QueryServiceConfig2 functions To query The service configuration.
;#SVC_QUERY_STATUS = $0004 ; Required To call The QueryServiceStatusEx function To ask The service Control manager about The Status of The service.
;#SVC_START = $0010 ; Required To call The StartService function To start The service.
;#SVC_STOP = $0020 ; Required To call The ControlService function To stop The service.
; ** Create Service service types
;#SVC_FILE_SYSTEM_DRIVER = $00000002 ; File system driver service.
;#SVC_KERNEL_DRIVER = $00000001 ; driver service.
#SVC_WIN32_OWN_PROCESS = $00000010 ; service that runs in its own process.
;#SVC_WIN32_SHARE_PROCESS = $00000020 ; service that shares a process With one Or more other services
#SVC_INTERACTIVE_PROCESS = $00000100 ; The service can interact With The desktop.
; ** Service Start Type
#SVC_AUTO_START = $00000002 ; A service started automatically by The service Control manager during system startup
;#SVC_BOOT_START = $00000000 ; A device driver started by The system loader. This Value is valid only For driver services.
;#SVC_DEMAND_START = $00000003 ; A service started by The service Control manager when A process calls The StartService function.
;#SVC_DISABLED = $00000004 ; A service that cannot be started. Attempts To start The service Result in The error code ERROR_SVC_DISABLED.
;#SVC_SYSTEM_START = $00000001 ; A device driver started by the IoInitSystem function. This value is valid only for driver services.
; ** Create Service error control
;#SVC_ERROR_CRITICAL = $00000003 ; The startup program logs The error in The event log, If possible.
; If The last-known-good configuration is being started, The startup operation fails.
; Otherwise, The system is restarted With The last-known good configuration.
;#SVC_ERROR_IGNORE = $00000000 ; The startup program ignores The error And continues The startup operation.
#SVC_ERROR_NORMAL = $00000001 ; The startup program logs The error in The event log but continues The startup operation.
;#SVC_ERROR_SEVERE = $00000002 ; The startup program logs The error in The event log. If The last-known-good configuration is being started,
; The startup operation continues. Otherwise, The system is restarted With The last-known-good configuration.
; ** Service Control Codes
;#SVC_CONTROL_CONTINUE = $00000003 ; Notifies a paused service that it should resume. The hService handle must have The SERVICE_PAUSE_CONTINUE access right.
;#SVC_CONTROL_PAUSE = $00000002 ; Notifies a service that it should pause. The hService handle must have The SERVICE_PAUSE_CONTINUE access right.
#SVC_CONTROL_STOP = $00000001 ; Notifies a service that it should stop. The hService handle must have The SERVICE_STOP access right.
; ** Service Status
;#SERVICE_CONTINUE_PENDING = $00000005 ; The service Continue is pending.
;#SERVICE_PAUSE_PENDING = $00000006 ; The service pause is pending.
;#SERVICE_PAUSED = $00000007 ; The service is paused.
#SERVICE_RUNNING = $00000004 ; The service is running.
;#SERVICE_START_PENDING = $00000002 ; The service is Starting.
;#SERVICE_STOP_PENDING = $00000003 ; The service is stopping.
#SERVICE_STOPPED = $00000001 ; The service is Not running.
; ** Error Codes
;#ERROR_ACCESS_DENIED = $5 ; The requested access was denied.
;#ERROR_CIRCULAR_DEPENDENCY = $423 ; A circular service dependency was specified.
;#ERROR_DUPLICATE_SERVICE_NAME = $436 ; The display name already exists in The service Control manager database either As A service name Or As another display name.
;#ERROR_INVALID_HANDLE = $6 ; The specified handle is invalid on closing SCM handler.
;#ERROR_INVALID_NAME = $7B ; The specified service name is invalid.
;#ERROR_INVALID_PARAMETER = $57 ; A parameter that was specified is invalid.
;#ERROR_INVALID_SERVICE_ACCOUNT = $421 ; The user account name specified in The lpServiceStartName parameter does Not exist.
;#ERROR_SERVICE_EXISTS = $431 ; The specified service already exists in This database.
;#ERROR_ACCESS_DENIED = $5 ; The requested access was denied.
;#ERROR_INVALID_HANDLE = $6 ; The specified handle is invalid on closing SCM handler.
;#ERROR_PATH_NOT_FOUND = $3 ; The service binary file could Not be found.
;#ERROR_SERVICE_ALREADY_RUNNING = $420 ; An instance of The service is already running.
;#ERROR_SERVICE_DATABASE_LOCKED = $41F ; The database is locked.
;#ERROR_SERVICE_DEPENDENCY_DELETED = $433 ; The service depends on a service that does Not exist Or has been marked For deletion.
;#ERROR_SERVICE_DEPENDENCY_FAIL = $42C ; The service depends on another service that has failed To start.
;#ERROR_SERVICE_DISABLED = $422 ; The service has been disabled.
;#ERROR_SERVICE_LOGON_FAILED = $42D ; The service did Not start due To a logon failure. This error occurs If The service is configured To run under An account that does Not have The "Log on as a service" right.
;#ERROR_SERVICE_MARKED_FOR_DELETE = $430 ; The service has been marked For deletion.
;#ERROR_SERVICE_NO_THREAD = $41E ; A thread could Not be created For The service.
;#ERROR_SERVICE_REQUEST_TIMEOUT = $41D ; The process For The service was started, but it did Not call StartServiceCtrlDispatcher, Or The thread that called StartServiceCtrlDispatcher may be blocked in a Control handler function.
;#ERROR_DATABASE_DOES_NOT_EXIST = $429 ; The specified database does Not exist.
;#ERROR_INVALID_PARAMETER =$57 ; A specified parameter is invalid.
Structure Status
dwServiceType.l
dwCurrentState.l
dwControlsAccepted.l
dwWin32ExitCode.l
dwServiceSpecificExitCode.l
dwCheckPoint.l
dwWaitHint.l
EndStructure
service.Status
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Vars ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Global lpMachineName = #Null
Global lpDatabaseName = #Null
Global scmDesiredAccess = #SCM_ALL_ACCESS
Global lpServiceName.s = "MyTestSvc"
Global lpDisplayName.s = "MyTestSvc Display Name"
Global svcDesiredAccess = #SVC_ALL_ACCESS
Global dwServiceType = #SVC_WIN32_OWN_PROCESS|#SVC_INTERACTIVE_PROCESS
Global dwStartType = #SVC_AUTO_START
Global dwErrorControl = #SVC_ERROR_NORMAL
Global lpBinaryPathName.s = Chr(34) + "c:\program files\nettax\interface\MyTestSvc.exe" + Chr(34)
Global lpLoadOrderGroup = #Null
Global lpdwTagId = #Null
Global lpDependencies = #Null
Global lpServiceStartName = #Null
Global lpPassword = #Null
Global dwNumServiceArgs = #Null
Global lpServiceArgVectors = #Null
Global dwControl = #SVC_CONTROL_STOP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Processing Code ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Procedure StartSvc()
scmHandler = OpenSCManager_(lpMachineName, lpDatabaseName, scmDesiredAccess)
If scmHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open SCM failed with error " + Str(LastError))
Else
svcHandler = OpenService_(scmHandler, lpServiceName, svcDesiredAccess)
If svcHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open Service failed with error " + Str(LastError))
Else
Result = QueryServiceStatus_(svcHandler, service.Status)
If Result = 0
LastError = GetLastError_()
MessageRequester("", "Query failed with error " + Str(LastError))
Else
If Not service\dwCurrentState = #SERVICE_RUNNING
Result = StartService_(svcHandler, dwNumServiceArgs, lpServiceArgVectors)
If Result = 0
LastError = GetLastError_()
MessageRequester("ERROR", "Start Service failed with error " + Str(LastError))
Else
WatchDog = 0
Repeat
QueryServiceStatus_(svcHandler, service.Status)
Delay(1000)
WatchDog = WatchDog +1
Until service\dwCurrentState = #SERVICE_RUNNING Or WatchDog => 10
If service\dwCurrentState <> #SERVICE_RUNNING And WatchDog => 10
MessageRequester("ERROR", "Could not Start the Service")
EndIf
EndIf
EndIf
EndIf
EndIf
Result = CloseServiceHandle_(svcHandler)
EndIf
Result = CloseServiceHandle_(scmHandler)
EndProcedure
Procedure CreateSvc()
scmHandler = OpenSCManager_(lpMachineName, lpDatabaseName, scmDesiredAccess)
If scmHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open SCM failed with error " + Str(LastError))
Else
svcHandler = CreateService_(scmHandler, lpServiceName, lpDisplayName, svcDesiredAccess, dwServiceType, dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, lpServiceStartName, lpPassword)
If svcHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Create Service failed with error " + Str(LastError))
Else
StartSvc()
EndIf
Result = CloseServiceHandle_(svcHandler)
EndIf
Result = CloseServiceHandle_(scmHandler)
EndProcedure
Procedure StopSvc()
scmHandler = OpenSCManager_(lpMachineName, lpDatabaseName, scmDesiredAccess)
If scmHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open SCM failed with error " + Str(LastError))
Else
svcHandler = OpenService_(scmHandler, lpServiceName, svcDesiredAccess)
If svcHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open Service failed with error " + Str(LastError))
Else
Result = QueryServiceStatus_(svcHandler, service.Status)
If Result = 0
LastError = GetLastError_()
MessageRequester("", "Query failed with error " + Str(LastError))
Else
If Not service\dwCurrentState = #SERVICE_STOPPED
Result = ControlService_(svcHandler, dwControl, service.Status)
If Result = 0
LastError = GetLastError_()
MessageRequester("", "Control Service failed with error " + Str(LastError))
Else
WatchDog = 0
Repeat
QueryServiceStatus_(svcHandler, service.Status)
Delay(1000)
WatchDog = WatchDog +1
Until service\dwCurrentState = #SERVICE_STOPPED Or WatchDog => 10
If service\dwCurrentState <> #SERVICE_STOPPED And WatchDog => 10
MessageRequester("ERROR", "Could not Stop the Service")
EndIf
EndIf
EndIf
EndIf
EndIf
Result = CloseServiceHandle_(svcHandler)
EndIf
Result = CloseServiceHandle_(scmHandler)
EndProcedure
Procedure RemoveSvc()
scmHandler = OpenSCManager_(lpMachineName, lpDatabaseName, scmDesiredAccess)
If scmHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open SCM failed with error " + Str(LastError))
Else
svcHandler = OpenService_(scmHandler, lpServiceName, svcDesiredAccess)
If svcHandler = #Null
LastError = GetLastError_()
MessageRequester("ERROR", "Open Service failed with error " + Str(LastError))
Else
StopSvc()
EndIf
Result = DeleteService_(svcHandler)
If Result = 0
LastError = GetLastError_()
MessageRequester("", "Delete Service failed with error " + Str(LastError))
EndIf
Result = CloseServiceHandle_(svcHandler)
EndIf
Result = CloseServiceHandle_(scmHandler)
EndProcedure
CreateSvc()