* Program:     QUITAPP.PRG
* Description: Client-side of remote termination of applications.
* Created:     07/11/2003
* Developer:   Gregory L Reichert
* Copyright:   Copyright (c) 2003 GLR software
*------------------------------------------------------------
* Id Date        By         			Description
*  1 07/11/2003  Gregory L Reichert     Initial Creation
*
*------------------------------------------------------------

*!*	Overview

*!*	The component is the client-side portion of a Remote Application Killer.
*!*	With the use of a shared table, an network administrator can determine
*!*	what workstation has what application running, and instruct that application
*!*	to quit.

*!*	An administrator can monitor which applications are running, and instruct them
*!*	termination themselves.

*!*	Instructions

*!*	This component is based on a Timer class with a one minute interval.  Each minute
*!*	the application check to see if the administrator wishs the application to
*!*	quit.  If discovered so, the countdown begins (default 10 minutes). During the
*!*	Countdown, a message is displayed notifing the user that the automatic termination of
*!*	the application is underway.  They can manual exit the application, or wait for the
*!*	automatic.  Either way, it is intended for the user to complete their current task.
*!*	At the end of the countdown, the application issues a QUIT command.

*!*	Call this routine, and a object reference is returned.  This object should
*!*	remain active throughout the life of the application.

*!*		PRIVATE oQuitApp
*!*		oQuitApp = QuitApp( "\\MyServer\MyDrive\CommonFiles\" )
*!*
*!*	When the administrator wish to terminate one or more application, they place
*!*	a True (.T.) in the "lQuit" field of the QuitApp.dbf table.  As the Application continues
*!*	countdown to automated termination, the "Remain" field indicates the number of minutes
*!*	remaining.  If the Admin changes the value of "Remain", the countdown continues from
*!*	that new value.  If a value less then zero (0) is entered, the application terminates
*!*	the next time the QuitApp timer is fired.


*!*	Two exposed method are provided to inform the routine that the application
*!*	is performing critical operations and can not be interupted.  These are called
*!*	EnterCritical() and LeaveCritical().  The EnterCritical() should be called when the
*!*	critical section begins, and the LeaveCritical() should be called when the section
*!*	ends.

*!*	The administrator can check to see a application is running, or if it crashed before hand,
*!*	by set the "aLiveTest" field of the QuitApp.dbf to False (.F.).  After a couple of minutes,
*!*	if the application is still alive, the field will revert to True (.T.).

*!*	The form called Admin_QuitApp.scx is used by the administrator to monitor and control the
*!*	remote applications.

*!*	=====================================================================================

LPARAMETERS tcPath, tcQuitName

RETURN CREATEOBJECT("QuitApp", tcPath, tcQuitName)


#DEFINE kQuitMax	10			&& Wait 10 minutes before auto-quit

*------------------------------------------------------------
* Description:	QuitApp class
*------------------------------------------------------------
* Id Date        By         			Description
*  1 07/11/2003  Gregory L Reichert     Initial Creation
*
*------------------------------------------------------------
DEFINE CLASS QuitApp AS TIMER

	INTERVAL = (60*1000)		&& check once a minute.
	ENABLE   = .T.
	cPath  	 = tcPath
	cQuitName  ="QuitApp"
	cQFile ="QuitApp"
	cAlias = "QuitApp"
			&& Full URN to QuitApp.dbf.  Must be at a shared network location for all running application to gain access.

	*------------------------------------------------------------
	* Description: Error Trap
	* Parameters:  internal
	* Return:      n/a
	* Use:         internal
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE ERROR( a,b,c )
		*-- ignore all error from this class
		RETURN
	ENDPROC

	*------------------------------------------------------------
	* Description: Initializes the timer
	* Parameters:  cPath: path to the shared QuitApp.dbf - path only
	* Return:      N/A
	* Use:         ox = CreateObject( "QuitApp","\\myserver\shared\CommonFiles\" )
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE INIT( cPath, cQuitName )
		LOCAL lc
		lc = SELECT()


		cPath = ADDBS(IIF(EMPTY(cPath),"", cPath))
		cQuitName = IIF(EMPTY(cQuitName),"QuitApp",JUSTSTEM(cQuitName))
		cQFile = cPath+cQuitName+".dbf"
		cAlias = "QuitApp"
		
		this.cPath = cPath
		this.cQuitName = cQuitName
		this.cQFile = cQFile
		this.cAlias = cAlias
		*-------------------------------------
		* create QuitApp table if missing.
		*-------------------------------------
		IF NOT FILE(this.cQFile)
			SELECT 0
			CREATE TABLE (this.cQFile) (ws c(40),ID N(10,0), cCaption c(100),lQuit L, remain N(3), Critical L, aLiveTest L)
			USE 
		ENDIF

		SELECT(lc)
	ENDPROC

	*------------------------------------------------------------
	* Description:	Timer routine
	* Parameters:   n/a
	* Return:		n/a
	* Use:			internal
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE TIMER


		LOCAL lc
		lc = SELECT()
		USE (this.cQFile) IN 0 SHARED ALIAS (this.cAlias)
		SELECT (this.cAlias)

		LOCATE FOR ID=_VFP.HWND AND cCaption=_VFP.CAPTION AND NOT DELETED()
		IF NOT FOUND()

			*-------------------------------------
			* Add an instence for this workstation / application
			INSERT INTO (this.cQFile) (ws,ID,cCaption,lQuit,remain, Critical, aLiveTest) ;
				VALUES ( UPPER(SYS(0)),_VFP.HWND, _VFP.CAPTION, .F., kQuitMax, .F., .T.)
		ENDIF

		*- Each time, reset the aLiveTest field.
		REPLACE aLiveTest WITH .T.

		IF NOT Critical AND TXNLEVEL()=0
			*- do only if not in Critical Section of the code,
			*  and not in a Transaction block
			IF lQuit
				*-------------------------------------
				* if still timing out, display remaining time.
				*-------------------------------------
				IF remain>0
					IF remain=kQuitMax
						* - if first time displaying the warning, force application on top.
						_SCREEN.ALWAYSONTOP=.T.
						_SCREEN.ALWAYSONTOP=.F.
					ENDIF
					*- decrement the counter, and display warning.
					REPLACE remain WITH remain -1
					osh=CREATEOBJECT('shell.application')
						osh.minimazeall
					_screen.windowstate=2
					WAIT WINDOW NOCLEAR NOWAIT "Programul se va inchide automat in " +ALLTRIM(STR(remain,10))+" minute."
					?? CHR(7)
					osh.undominimazeall
					RELEASE osh
				ELSE
					*-------------------------------------
					* otherwise, quit the application.
					*-------------------------------------
					USE IN (this.cAlias)
					CLEAR EVENTS
					glQuit = .T.
					QUIT
				ENDIF
			ELSE
				*-------------------------------------
				* if nolonger quiing, reset counter.
				*-------------------------------------
				REPLACE remain WITH kQuitMax
				WAIT CLEAR
			ENDIF
		ENDIF

		USE IN (this.cAlias)
		THIS.RESET
		SELECT(lc)
	ENDPROC

	*------------------------------------------------------------
	* Description: Called when entering a Critical Section of the code.
	* Parameters:  n/a
	* Return:      True
	* Use:         <object>.EnterCritical
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE EnterCritical()
		LOCAL lc
		lc = SELECT()
		USE (this.cQFile) IN 0 SHARED ALIAS (this.cAlias)
		SELECT (this.cAlias)

		UPDATE (this.cQFile) SET Critical=.T. WHERE ID=_VFP.HWND AND cCaption=_VFP.CAPTION

		USE IN (this.cAlias)
		SELECT(lc)
	ENDPROC

	*------------------------------------------------------------
	* Description:	Called when exitting a Critical Section of the code.
	* Parameters:  	n/a
	* Return:		True
	* Use:			<object>.LeaveCritical
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE LeaveCritical()
		LOCAL lc
		lc = SELECT()
		USE (this.cQFile) IN 0 SHARED ALIAS (this.cAlias)
		SELECT (this.cAlias)

		UPDATE (this.cQFile) SET Critical=.F. WHERE ID=_VFP.HWND AND cCaption=_VFP.CAPTION

		USE IN (this.cAlias)
		SELECT(lc)
	ENDPROC

	*------------------------------------------------------------
	* Description:	Destroy this object
	* Parameters:  	n/a
	* Return:		n/a
	* Use:			internal
	*------------------------------------------------------------
	* Id Date        By         			Description
	*  1 07/11/2003  Gregory L Reichert     Initial Creation
	*
	*------------------------------------------------------------
	PROCEDURE DESTROY
		*-----------------------------------------------
		* On destroy, remove the application reference from the QuitApp table.
		*-----------------------------------------------
		LOCAL lc
		lc = SELECT()
		USE (this.cQFile) IN 0 SHARED ALIAS (this.cAlias)
		SELECT (this.cAlias)
		
		DELETE FROM (this.cQFile) WHERE ID=_VFP.HWND AND cCaption=_VFP.CAPTION

		USE IN (this.cAlias)
		SELECT(lc)
	ENDPROC

ENDDEFINE



&& ------------------------------INCEPUT: Quit_Automat ------------------------------ 
*!* Procedura:  Quit_Automat
*!* Parametri: tlQuit
*!* Data/Ora generarii: 19/02/2004 12:48
*!* Autor: MARIUS.MUTU
PROCEDURE  Quit_Automat
LPARAMETERS tlQuit

IF tlQuit
	QUIT
ENDIF 

ENDPROC
&& ------------------------------SFARSIT: Quit_Automat ------------------------------ 

* Eof QUITAPP.PRG
***************************
*!*	FUNCTION AppInstance
*!*	PARAMETERS WindowName 

*!*	#DEFINE GW_OWNER 4
*!*	#DEFINE GW_HWNDFIRST 0
*!*	#DEFINE GW_HWNDNEXT 2
*!*	#DEFINE SW_MAXIMIZE 3
*!*	#DEFINE SW_NORMAL 1

*!*	DECLARE integer SetForegroundWindow in win32api long lnhWnd
*!*	DECLARE integer GetWindowText in win32api integer, string, integer
*!*	DECLARE integer GetWindow in win32api integer,INTEGER
*!*	DECLARE integer IsWindowVisible in win32api integer
*!*	DECLARE integer GetActiveWindow in win32api 
*!*	DECLARE integer ShowWindow in user32 INTEGER lnhWnd, INTEGER lnCmdShow

*!*	IsWindEx = .F.
*!*	if len(WindowName) < 1
*!*		return .t.
*!*	endif

*!*	foxhwnd = GetActiveWindow()
*!*	hwndNext = GetWindow(foxhwnd,GW_HWNDFIRST)

*!*	DO WHILE hwndNext <> 0
*!*		IF (hwndnext <> foxhwnd .AND. GetWindow(hwndnext,GW_OWNER) = 0)
*!*			Stuffer = SPACE(64)
*!*			x = GetWindowText(hwndnext,@Stuffer,64)
*!*			IF WindowName $ Stuffer
*!*				IsWindEx = .T.
*!*				=SetForegroundWindow(hwndnext)
*!*				=ShowWindow(hwndNext,SW_MAXIMIZE)
*!*				EXIT
*!*			ENDIF
*!*		ENDIF
*!*		hwndNext = GetWindow(hwndnext,GW_HWNDNEXT)
*!*	ENDDO

*!*	RETURN IsWindEx
*!*	ENDFUNC 