Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Start/Stop Spooler and wait it out
Message
De
28/08/2019 14:26:59
Mike Yearwood
Toronto, Ontario, Canada
 
 
À
Tous
Information générale
Forum:
Visual FoxPro
Catégorie:
Fonctions Windows API
Titre:
Start/Stop Spooler and wait it out
Divers
Thread ID:
01670394
Message ID:
01670394
Vues:
73
VFP 9 SP2, remoting to a development virtual machine.

I grabbed a copy of the code from GitHub - thanks to Anatoliy for posting it - and am attempting to use a loop to determine when the service changed to the status I requested.

It seems I have to release both the WS and SRV objects to get accurate results. It's slow. So my "animation" doesn't animate quickly, but it does detect that the service stopped/started.

I tried to keep the WS object and release+recreate the srv object inside the loop, but it never seems to detect that Windows has started or stopped the service. I cannot use recursion, because it can take a long time to start the spooler.

What can I do to get accurate results from the srv object without reinstantiating both?

I'm calling CallWindowsService.prg like so.
?CallWindowsService("Spooler","STOP")
?CallWindowsService("Spooler","START")
*CallWindowsService.prg
LPARAMETERS tcService,tcAction
#DEFINE SERVICE_WIN32 0x30  
#DEFINE SERVICE_RUNNING 4  
_vfp.aUTOYIELD=.t.
SET ESCAPE ON
ON ESCAPE
SET PROCEDURE TO WINDOWSSERVICECLASS.PRG additive

LOCAL ws As winservices, srv As winservice  

STORE 1 TO tnAnimate
STORE "" TO lcCurrentStatus, lcStatus

DO WHILE m.lcCurrentStatus = m.lcStatus

	ws = CREATEOBJECT("winservices", Null, Null, SERVICE_WIN32)
	srv = ws.GetService(m.tcService)
	IF ISNULL(srv)  
		? m.tcService + " service is not found on this computer"  
		EXIT
	ENDIF

	if m.tnAnimate=1
		m.tnAnimate=2
		m.tcAnimate="|"
	else
		m.tnAnimate=1
		m.tcAnimate="-"
	endif

	DO case
	CASE m.tcAction="START"
		m.lcCurrentStatus="stopped"
		srv.StartService()  
	CASE m.tcAction="STOP"
		m.lcCurrentStatus="running"
		srv.StopService()
	CASE m.tcAction="PAUSE"
		m.lcCurrentStatus=IIF(srv.currentstate=SERVICE_RUNNING,"running", "stopped")
		srv.PauseService()  
	CASE m.tcAction="STATUS"
	ENDCASE

	WAIT WINDOW NOWAIT NOCLEAR m.tcService + " service is being " + m.tcAction + IIF(m.tcAction='STOP','P','') + 'ED ' + m.tcAnimate
	m.lcStatus=IIF(srv.currentstate=SERVICE_RUNNING,"running", "stopped")
	FASTDOEVENTS()
	srv=.NULL.
	ws=.NULL.
ENDDO
WAIT WINDOW NOWAIT m.tcService + " service is " + m.lcStatus + "."
RETURN m.lcStatus

FUNCTION FastDoEvents
  KEYBOARD " "
  =INKEY()
  DOEVENTS
RETURN
The WindowsService Class definition is in WindowsServiceClass.prg
DEFINE CLASS winservices As Collection
#DEFINE SC_MANAGER_CONNECT 1
#DEFINE SC_MANAGER_LOCK 8
#DEFINE SC_MANAGER_ENUMERATE_SERVICE 4

#DEFINE SERVICE_ACTIVE 1
#DEFINE SERVICE_INACTIVE 2
#DEFINE SERVICE_DRIVER 0x0b
#DEFINE SERVICE_WIN32 0x30

#DEFINE SERVICE_STOPPED 1
#DEFINE SERVICE_RUNNING 4
#DEFINE SERVICE_PAUSED 7

#DEFINE SERVICE_START 0x10
#DEFINE SERVICE_STOP 0x20
#DEFINE SERVICE_PAUSE_CONTINUE 0x40
#DEFINE SERVICE_INTERROGATE 0x80

#DEFINE SERVICE_CONTROL_STOP 1
#DEFINE SERVICE_CONTROL_PAUSE 2
#DEFINE SERVICE_CONTROL_INTERROGATE 4

PROTECTED hManager, hLock
	hManager=0
	hLock=0
	errorcode=0

PROCEDURE Init(cComputerName, cDatabaseName, nServiceType)
	THIS.declare
	IF VARTYPE(m.cComputerName) <> "C"
		cComputerName=Null
	ENDIF
	IF VARTYPE(m.cDatabaseName) <> "C"
		cDatabaseName=Null
	ENDIF

	THIS.hManager = OpenSCManager(m.cComputerName, m.cDatabaseName,;
		BITOR(SC_MANAGER_CONNECT, SC_MANAGER_LOCK,;
			SC_MANAGER_ENUMERATE_SERVICE))

	THIS.errorcode = IIF(THIS.hManager=0, GetLastError(), 0)

	IF VARTYPE(m.nServiceType)="N"
		THIS.EnumServices(m.nServiceType)
	ENDIF

PROCEDURE EnumServices(nServiceType)
#DEFINE ENUM_SERVICE_STATUS_SIZE 36
#DEFINE SERVICE_STATUS_SIZE 28

	THIS.ClearEnum

	LOCAL nBufsize, nBytesNeeded, nCount, hResume, nServiceStatus
	STORE 0 TO nBytesNeeded, nCount, hResume
	nServiceStatus = BITOR(SERVICE_ACTIVE, SERVICE_INACTIVE)

	= EnumServicesStatus(THIS.hManager, nServiceType,;
		nServiceStatus, 0, 0,;
		@nBytesNeeded, @nCount, @hResume)

	nBufsize = nBytesNeeded
	hBuffer = LocalAlloc(0, nBufsize)
	hResume = 0

	= EnumServicesStatus(THIS.hManager, nServiceType,;
		nServiceStatus, hBuffer, nBufsize,;
		@nBytesNeeded, @nCount, @hResume)

	LOCAL cBuffer, cService, nIndex, hPtr, hServiceName
	cBuffer = REPLICATE(CHR(0), nBufsize)
	= MemToStr(@cBuffer, hBuffer, nBufsize)

	FOR nIndex=0 TO nCount-1
		LOCAL oService As winservice
		oService = CREATEOBJECT("winservice",;
			THIS, m.hBuffer, @cBuffer, nIndex)

		THIS.Add(oService, oService.servicename)
		oService=Null
	NEXT
	= LocalFree(hBuffer)
RETURN .T.

PROCEDURE Destroy
	IF THIS.hManager <> 0
		THIS.ClearEnum
		THIS.UnlockDatabase
		= CloseServiceHandle(THIS.hManager)
		THIS.hManager=0
	ENDIF

FUNCTION GetService(vService) As winservice
	LOCAL oService As winservice, ex As Exception
	TRY
		oService = THIS.Item(vService)
	CATCH TO ex
		THIS.errorcode = ex.Message
		oService = Null
	ENDTRY
RETURN oService

PROTECTED PROCEDURE ClearEnum
	DO WHILE THIS.Count > 0
		LOCAL itm As winservice
		itm = THIS.Item(1)
		itm = Null
		THIS.Remove(1)
	ENDDO

FUNCTION GetHManager()
RETURN THIS.hManager

FUNCTION IsDatabaseLocked
RETURN (THIS.hLock <> 0)

FUNCTION LockDatabase
	IF THIS.hLock = 0
		THIS.hLock = LockServiceDatabase(THIS.hManager)
	ENDIF
	THIS.errorcode = IIF(THIS.hLock=0, GetLastError(), 0)
RETURN (THIS.hLock <> 0)

FUNCTION UnlockDatabase
	IF THIS.hLock <> 0
		= UnlockServiceDatabase(THIS.hLock)
		THIS.hLock = 0
	ENDIF
RETURN (THIS.hLock = 0)

PROTECTED PROCEDURE declare
	DECLARE INTEGER GetLastError IN kernel32
	DECLARE INTEGER LockServiceDatabase IN advapi32 INTEGER hSCManager
	DECLARE INTEGER CloseServiceHandle IN advapi32 INTEGER hSCObject
	DECLARE INTEGER UnlockServiceDatabase IN advapi32 INTEGER ScLock
	DECLARE INTEGER LocalFree IN kernel32 INTEGER hMem

	DECLARE RtlMoveMemory IN kernel32 As StrToMem;
		INTEGER Dest, STRING @Src, INTEGER nLength

	DECLARE RtlMoveMemory IN kernel32 As MemToStr;
		STRING @dest, INTEGER src, INTEGER nLength

	DECLARE INTEGER LocalAlloc IN kernel32;
		INTEGER uFlags, INTEGER uBytes

	DECLARE INTEGER OpenSCManager IN advapi32;
		STRING lpMachineName, STRING lpDatabaseName,;
		LONG dwDesiredAccess

	DECLARE INTEGER OpenService IN advapi32;
		INTEGER hSCManager, STRING lpServiceName,;
		LONG dwDesiredAccess

	DECLARE INTEGER EnumServicesStatus IN advapi32;
		INTEGER hSCManager, LONG dwServiceType, LONG dwServiceState,;
		INTEGER lpServices, LONG cbBufSize, LONG @pcbBytesNeeded,;
		LONG @lpServicesReturned, LONG @lpResumeHandle

	DECLARE INTEGER StartService IN advapi32;
		INTEGER hService, LONG dwNumServiceArgs,;
		INTEGER lpServiceArgVectors

	DECLARE INTEGER ControlService IN advapi32;
		INTEGER hService, LONG dwControl,;
		STRING @lpServiceStatus
ENDDEFINE

DEFINE CLASS winservice As Session
PROTECTED oWinServices, hService
	hService=0
	errorcode=0
	servicename=""
	displayname=""
	servicetype=0
	currentstate=0
	controlsaccepted=0
	win32exitcode=0
	serviceexitcode=0
	checkpoint=0
	waithint=0

PROCEDURE Init(oWinServices, hBuffer, cBuffer, nIndex)
	THIS.oWinServices = m.oWinServices

	LOCAL cService, hPtr
	cService = SUBSTR(cBuffer,;
		(nIndex*ENUM_SERVICE_STATUS_SIZE)+1,;
		ENUM_SERVICE_STATUS_SIZE)

	THIS.ConvertStatusInfo(SUBSTR(cService, 9))

	hPtr = buf2dword(SUBSTR(cService, 1,4)) - hBuffer + 1
	THIS.servicename = THIS.GetName(@cBuffer, hPtr)

	hPtr = buf2dword(SUBSTR(cService, 5,4)) - hBuffer + 1
	THIS.displayname = THIS.GetName(@cBuffer, hPtr)

PROCEDURE Destroy
	THIS.CloseServiceHandle

PROTECTED FUNCTION GetName(cBuffer, hPtr)
	IF (hPtr <= 0) OR hPtr >= LEN(cBuffer)
		RETURN ""
	ENDIF

	LOCAL cName, ch
	cName = ""
	DO WHILE hPtr < LEN(cBuffer)
		ch = SUBSTR(cBuffer, m.hPtr, 1)
		IF m.ch = CHR(0)
			EXIT
		ENDIF
		cName = cName + m.ch
		hPtr = hPtr + 1
	ENDDO
RETURN cName

FUNCTION StartService
* 1055=ERROR_SERVICE_DATABASE_LOCKED
* A call to the StartService function to start a service
* in a locked database fails. No other service control manager
* functions are affected by a lock.
	THIS.errorcode = 0
	IF NOT THIS.OpenServiceHandle(0x90)
		RETURN .F.
	ENDIF
	
	LOCAL LockStatus
	LockStatus = THIS.oWinServices.IsDatabaseLocked()

	IF THIS.oWinServices.UnlockDatabase()
		IF StartService(THIS.hService, 0,0) = 0
			THIS.errorcode = GetLastError()
		ENDIF
		IF m.LockStatus
			THIS.oWinServices.LockDatabase
		ENDIF
	ENDIF
	THIS.CloseServiceHandle
RETURN (THIS.errorcode <> 0)

PROCEDURE StopService
	THIS.ControlService(SERVICE_STOP, SERVICE_CONTROL_STOP)

PROCEDURE PauseService
	THIS.ControlService(SERVICE_PAUSE_CONTINUE, SERVICE_CONTROL_PAUSE)

PROTECTED PROCEDURE CloseServiceHandle
	IF THIS.hService <> 0
		= CloseServiceHandle(THIS.hService)
		THIS.hService = 0
	ENDIF

PROTECTED FUNCTION OpenServiceHandle(nAccess)
	THIS.CloseServiceHandle
	THIS.hService = OpenService(THIS.oWinServices.GetHManager(),;
		THIS.servicename, nAccess)
	THIS.errorcode = IIF(THIS.hService=0, 0, GetLastError())
RETURN (THIS.hService <> 0)

PROTECTED FUNCTION ControlService(nOpenFlag, nCtrlFlag)
	THIS.errorcode = 0
	IF NOT THIS.OpenServiceHandle(nOpenFlag)
		RETURN .F.
	ENDIF

	LOCAL cStatusInfo
	cStatusInfo = REPLICATE(CHR(0), SERVICE_STATUS_SIZE)
	IF ControlService(THIS.hService, nCtrlFlag, @cStatusInfo) = 0
		THIS.errorcode = GetLastError()
	ENDIF
	THIS.CloseServiceHandle
RETURN .T.

FUNCTION UpdateStatusInfo
	THIS.errorcode = 0
	IF NOT THIS.OpenServiceHandle(SERVICE_INTERROGATE)
		RETURN .F.
	ENDIF
	
	LOCAL cStatusInfo
	cStatusInfo = REPLICATE(CHR(0), SERVICE_STATUS_SIZE)
	
	IF ControlService(THIS.hService,;
		SERVICE_CONTROL_INTERROGATE, @cStatusInfo) = 0
		THIS.errorcode = GetLastError()
	ELSE
		THIS.ConvertStatusInfo(cStatusInfo)
	ENDIF
	THIS.CloseServiceHandle
RETURN .T.

PROTECTED PROCEDURE ConvertStatusInfo(cStatusInfo)
	THIS.servicetype = buf2dword(SUBSTR(cStatusInfo, 1,4))
	THIS.currentstate = buf2dword(SUBSTR(cStatusInfo, 5,4))
	THIS.controlsaccepted = buf2dword(SUBSTR(cStatusInfo, 9,4))
	THIS.win32exitcode = buf2dword(SUBSTR(cStatusInfo, 13,4))
	THIS.serviceexitcode = buf2dword(SUBSTR(cStatusInfo, 17,4))
	THIS.checkpoint = buf2dword(SUBSTR(cStatusInfo, 21,4))
	THIS.waithint = buf2dword(SUBSTR(cStatusInfo, 25,4))

ENDDEFINE

FUNCTION buf2dword(lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
	BitLShift(Asc(SUBSTR(lcBuffer, 2,1)),  8) +;
	BitLShift(Asc(SUBSTR(lcBuffer, 3,1)), 16) +;
	BitLShift(Asc(SUBSTR(lcBuffer, 4,1)), 24)  
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform