* 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: .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: .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