Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss. print.
REMOTE SHUTDOWN OF APPLICATIONS

The Problem
The applications are created for the users and are started by the users. The application, being is started by the user, can work since morning and till evening. The user at this time can carefree leave his office to have dinner or to confer in an adjacent department.
But here the ill luck, just in it is high time you, as the manager of system or as the developer, should change structures of the tables or to execute urgent works on a server. What to do with the working application? To reset connection of the user or to shutdown the server, despite of the application which still is working and is using tables? It can result in loss of the data. Should you wait a return of the user? But other clients expecting end of works can suffer from it. Should you run to the user's office and unload the program? The good idea, if for this purpose is not necessary to overcome tens of miles. The eternal question: «What to do?»
 
The Solution


Solution, as ever, is evident. It is necessary to provide a sending mechanism of command by the system manager, a receiving of this command by application, and an executing of shutdown.

No, it is not my original idea. You could read that it is enough to the manager to place into some directory some file, and it is enough to the application to locate this file and to shutdown itself without user’s operations.
It would be very easy to realize this, but we must consider the following conditions:
Every application has own specificity and it must be unloaded by individual way. Within the framework of one class we must provide an adjustment of the each concrete application. It is possible that the program system consists of some number of the linked or non-linked applications; therefore an opportunity of unloading of all applications in one operation must exist just as an opportunity to unload the selected specific application. The applications should not disappear from the screen suddenly. The user needs to receive the message about the reasons of an unloading of the application or about the prospective time of renewal of work. The user should have a delay of a unloading of the application to have time to make a hand-operated unloading of the application how he does it usually. At the same time he needs see, how many time remained before automatic ending.

An instrument of automatic shutdown of the application must has some abilities to realize these requirements:
An instance of a shutdown class must be invisible until the unloading command will be received. The instance of class must react to two events: The first event is an appearance of file of the unloading command for concrete application in specified directory.nts: The second event is an appearance of file of the unloading command for all applications in specified directory. The instance of class must store a reference to the procedure of termination of the application. This procedure will emulate user's operations to finish the application. The instance of class must become visible after reception of the unloading command. The command file can contain text of a message, which will be read by this instance. This message will be showed in a notification window for the user. In the notification window we should place a process indicator, which will be show time, which stayed up to a start of the finishing procedure. After the expiration of a waiting time of actions of the user, the instance of class must start the finishing procedure. The instance of class must operate both in the application with main window, and in the application based on top-level form. The appearance of the notification window of the user can be as in the following figure:



Process indicator
It is possible to use any available class of the process indicator or an appropriate ActiveX control. Let's assume, that we have not neither that, nor another. It is not very difficult to create the process indicator. It is enough to use the container, as a base class, and to place in it objects representing the indicator. It can be a collection of objects of the SHAPE class. The first object will show common length of process, another will point to the current value of process. The definition of such class can look like this:


DEFINE CLASS progressbar AS container
    ** Length of bar of process indicator
    Width = 100
    ** Height of bar of process indicator
    Height = 20
    BackStyle = 0
    BorderWidth = 0
    ** Max value of process variable
    MaxValue = (this.Width)
    ** Current value of process variable 
    CurrentValue = 0
    Name = "progressbar"

** This object represents common length of process
ADD OBJECT border AS shape WITH ;
    ** To place on all area of the container
    Top = 0, ;
    Left = 0, ;
    Height = (this.parent.Height), ;
    Width = (this.parent.Width), ;
    Name = "Border"

ADD OBJECT bar AS shape WITH ;
    ** To place on height of the container with zero length
    Top = 0, ;
    Left = 0, ;
    Height = (this.parent.Height), ;
    Width = 0, ;
    BorderStyle = 0, ;
    BorderWidth = 0, ;
    Curvature = 0, ;
    FillStyle = 0, ;
    FillColor = RGB(0,0,255), ;
    Name = "Bar"

PROCEDURE currentvalue_assign
    ** It is necessary to redraw the object of the current value
    ** after changing of the current value of parameter
    LPARAMETERS vNewVal
    ** The checking of the value of the accepted parameter
    do case
        case m.vNewVal<0
            THIS.CurrentValue = 0
        case m.vNewVal>0 and m.vNewVal<=THIS.MaxValue
            THIS.CurrentValue = m.vNewVal
        case m.vNewVal>THIS.MaxValue
            THIS.CurrentValue = THIS.MaxValue
    endcase
    ** Redraw object
    THIS.Bar.Width=int(THIS.Width*(THIS.CurrentValue/THIS.MaxValue))
ENDPROC

PROCEDURE Init
    ** An adjustment of objects on the size of the container
    this.Bar.Height=this.Height
    this.Bar.Width=0
    this.Border.Height=this.Height
    this.Border.Width=this.Width
ENDPROC

ENDDEFINE

Notification window of user
The notification window must appear in screen after reception of the unloading command. There are the process indicator, the notifying text and red blinking light in this window. We will use this light to attract an attention of user.
After this event the process indicator must be started. The finishing procedure will have been started when the process indicator will have reached its max value.
Approximate code for this class:
DEFINE CLASS alarmwindow AS form
Height = 218
Width = 298
Desktop = .T.
DoCreate = .T.
AutoCenter = .T.
BorderStyle = 2
Caption = "Remote Shutdown"
TitleBar = 1
AlwaysOnTop = .T.
BackColor = RGB(255,255,128)
MaxValue = (this.Progress.Width)
CurrentValue = 0
lightFlash = 0
Name = "alarmwindow"
ParentRef = .F.

ADD OBJECT label1 AS label WITH ;
	FontBold = .F., ;
	FontSize = 9, ;
	WordWrap = .T., ;
	Alignment = 2, ;
	BackStyle = 0, ;
	Caption = "Attention! "+;
	          "This application will be shut down. "+;
	          "Save a data and exit!", ;
	Height = 33, ;
	Left = 26, ;
	Top = 5, ;
	Width = 265, ;
	Name = "Label1"

** The light is ON
ADD OBJECT lighton AS image WITH ;
	Picture = "red.bmp", ;
	BackStyle = 0, ;
	Height = 12, ;
	Left = 11, ;
	Top = 8, ;
	Width = 12, ;
	Name = "LightOn"

** The light is OFF
ADD OBJECT lightoff AS image WITH ;
	Picture = "grey.bmp", ;
	BackStyle = 0, ;
	Enabled = .T., ;
	Height = 12, ;
	Left = 11, ;
	Top = 8, ;
	Visible = .F., ;
	Width = 12, ;
	Name = "LightOff"

** The timer of a waiting time of the user
ADD OBJECT timer AS timer WITH ;
	Top = 11, ;
	Left = 270, ;
	Height = 23, ;
	Width = 23, ;
	Enabled = .F., ;
	Interval = 500, ;
	Name = "Timer"

** An object of the process indicator
ADD OBJECT progress AS progressbar WITH ;
	Top = 45, ;
	Left = 6, ;
	Width = 285, ;
	Height = 20, ;
	Name = "Progress", ;
	Border.DefHeight = "", ;
	Border.DefWidth = "", ;
	Border.BackStyle = 0, ;
	Border.Name = "Border", ;
	Bar.DefHeight = "", ;
	Bar.Name = "Bar"

ADD OBJECT inform AS editbox WITH ;
	FontBold = .F., ;
	Alignment = 0, ;
	BackStyle = 1, ;
	BorderStyle = 1, ;
	Enabled = .F., ;
	Height = 138, ;
	Left = 6, ;
	ReadOnly = .F., ;
	Top = 78, ;
	Width = 288, ;
	DisabledBackColor = RGB(255,255,128), ;
	DisabledForeColor = RGB(0,0,0), ;
	Name = "Inform"

PROCEDURE maxvalue_access
	RETURN THIS.Progress.MaxValue
ENDPROC

PROCEDURE maxvalue_assign
	LPARAMETERS vNewVal
	THIS.Progress.MaxValue = m.vNewVal
ENDPROC

PROCEDURE currentvalue_access
	RETURN THIS.Progress.CurrentValue
ENDPROC

PROCEDURE currentvalue_assign
	LPARAMETERS vNewVal
	THIS.Progress.CurrentValue = m.vNewVal
ENDPROC

PROCEDURE start
	this.Timer.Enabled=.T.
ENDPROC

PROCEDURE Init
	LPARAMETERS lnTimeOut
	if type('lnTimeOut')!='N'
		this.MaxValue=lnTimeOut
	endif
ENDPROC

PROCEDURE timer.Timer
	this.parent.LightOn.Visible=!this.parent.LightOn.Visible
	this.parent.LightOff.Visible=!this.parent.LightOff.Visible
	local lnLightFlash
	lnLightFlash=this.parent.LightFlash
	this.parent.LightFlash=this.parent.LightFlash+1
	this.parent.CurrentValue=this.parent.CurrentValue+this.Interval
	if this.parent.CurrentValue>=this.parent.MaxValue
		local loShutDown
		loShutDown=this.parent.ParentRef
		loShutDown.TimeOut()
		this.parent.Release()
	endif
ENDPROC

PROCEDURE inform.Init
	this.Value='The application will be shutdown to update it'
ENDPROC

ENDDEFINE

The notification window and an application based on Top Level Form
Now we shall define a subclass of notification window. The goal of it is a working in an application based on Top Level Form, without FP's main window.
DEFINE CLASS alarmwindowtlf AS alarmwindow 
        Desktop = .F. 
        ShowWindow = 1 
        DoCreate = .T. 
        Name = "alarmwindowtlf" 
        Label1.Name = "Label1" 
        LightOn.Height = 12 
        LightOn.Width = 12 
        LightOn.Name = "LightOn" 
        LightOff.Height = 12 
        LightOff.Width = 12 
        LightOff.Name = "LightOff" 
        Timer.Name = "Timer" 
        PROGRESS.Border.DefHeight = "" 
        PROGRESS.Border.DefWidth = "" 
        PROGRESS.Border.Name = "Border" 
        PROGRESS.Bar.DefHeight = "" 
        PROGRESS.Bar.Name = "Bar" 
        PROGRESS.Name = "PROGRESS" 
ENDDEFINE 

Class of the remote shutdown of an application
So, we can define class of the remote shutdown of an application. Just it must work invisibly all the time when the application is running, and locate the command files, and start the notification window, and unload the application without user's operations, if it is necessary.
DEFINE CLASS powershutdownms AS timer

Height = 23
Width = 23
Enabled = .F.
** Interval of search of a file (by default)
Interval = 60000
** Name of a file for a unloading of all applications
systemshutdownfile = "ShutDown.txt"
** Name of a file for a unloading of the concrete application
taskshutdownfile = NULL
** Waiting time of actions of the user
shutdownwaittime = 180000
** Name of the finishing procedure
shutdownhandler = NULL
PROTECTED alarmmess
alarmmess = NULL
Name = "powershutdownms"
PROTECTED inform

** Start the notification window
PROCEDURE StartAlarm
	local loAlarm
	this.AlarmMess=createobject('AlarmWindow')
	loAlarm=this.AlarmMess
	loAlarm.Inform.Value=this.Inform
	loAlarm.MaxValue=this.ShutDownWaitTime
	loAlarm.ParentRef=this
	loAlarm.Show()
	loAlarm.Start()
ENDPROC

** Processing of event of end of expectation of the user
PROCEDURE timeout
	if !isnull(this.AlarmMess)
		local loAlarmMess
		loAlarmMess=this.AlarmMess
		if !isnull(this.ShutDownHandler)
			if type('this.ShutDownHandler')='C'
				local lcShutDownHandler
				lcShutDownHandler=this.ShutDownHandler
				do &lcShutDownHandler
			else
				this.ShutDown()
			endif
		else
			this.ShutDown()
		endif
	endif
ENDPROC

** Finishing procedure (by default)
PROCEDURE shutdown
	quit
ENDPROC

** Search of a command file
PROCEDURE Timer
	local llShutDown
	llShutDown=.F.
	if file(this.SystemShutDownFile)
		this.Inform=filetostr(this.SystemShutDownFile)
		llShutDown=.T.
	else
		if !isnull(this.TaskShutDownFile)
			if type('this.TaskShutDownFile')='C'
				if file(this.TaskShutDownFile)
					this.Inform=filetostr(this.TaskShutDownFile)
					llShutDown=.T.
				endif
			endif
		endif
	endif
	if llShutDown
		this.Enabled=.F.
		this.StartAlarm()
	endif
ENDPROC

PROCEDURE Init
	this.Inform=''
ENDPROC

ENDDEFINE

The class of remote shutdown and an application based on Top Level Form
The difference of this subclass from its parent is only code of method, called StartAlarm, of a starting of the notification window.
DEFINE CLASS powershutdowntlf AS powershutdownms

Name = "powershutdowntlf"

PROCEDURE startalarm
local loAlarm
this.AlarmMess=createobject('AlarmWindowTLF')
loAlarm=this.AlarmMess
loAlarm.Inform.Value=this.Inform
loAlarm.MaxValue=this.ShutDownWaitTime
loAlarm.ParentRef=this
loAlarm.Show()
loAlarm.Start()
ENDPROC

ENDDEFINE

The Conclusion
By placing a code for creation of object of this class in the MAIN-module of the application, we shall ensure a remote unloading of the application and we shall untie our hands ourselves. The example of such code can look as follows:
** MAIN
PROCEDURE MAIN
    PUBLIC goPSD
    SET CLASSLIB TO SHUTDOWN
    goPSD=createobject("PowerShutDownMS")
    ** Interval for search of a command file = 3 minutes
    goPSD.Interval=3*60*1000
    ** Waiting time of actions of the user = 5 minutes
    goPSD.ShutDownWaitTime=5*60*1000
    ** Finishing procedure
    goPSD.ShutDownHandler=’Finish’
    goPSD.Enabled=.T.
    ** 
    ** Code of initialization of the application
    ** 
ENDPROC

PROCEDURE Finish
    ** 
ENDPROC

Download code
You can download this article and the program sample here. The download is a zipfile. Its size is 19,557 bytes.

ABOUT THE AUTHOR: VLADIMIR TRUKHIN

Vladimir Trukhin Vladimir Trukhin is Visual FoxPro developer and author. He has been developing program systems and applications since 1983. He specializes in software system development, user interface design, object oriented programming, developer support, training and other services. Vladimir has written for FoxTalk magazine. Visual FoxPro is his everyday tool and assistant. You can contact him by e-mail at vlt@votges.ru. You can find additional information about Vladimir on home page at http://www.geocities.com/vhpcg/resume.html.

FEEDBACK

Jyothish KV @ 8/30/2007 11:10:54 AM
Excellent!! Definitely this article is very useful what I was looking for... Thanks a lot Vladimir.

Amatus Edwards @ 11/13/2008 10:59:41 PM
I have that need but has used a more elaborate solution. I built an Application Server in Foxpro using Winsock. When my application starts by a client, the client connects to the application server. With this connection established, I can send any command to the client from the Server to do anything that I want. oSock.SendCmd('oApp.shutdown') is an example. When the client receives that message 'oApp.Shutdown' in a String, it does a macro substitution.

lcCmdReceived = oSock.dataarival
&lcCmdReceived.

Aysha Hussain @ 1/8/2012 3:41:38 PM
hi VLADIMIR TRUKHIN

excellent job...we were searching for this solution long time...thanks a lot sir....here things are fine ...but how do we know that how many users are using our application....your answer on this will be highly appreciated

with regards
aysha h

Aysha Hussain @ 1/8/2012 3:41:44 PM
hi VLADIMIR TRUKHIN

excellent job...we were searching for this solution long time...thanks a lot sir....here things are fine ...but how do we know that how many users are using our application....your answer on this will be highly appreciated

with regards
aysha hussain



Your Name: 
Your Feedback: 

Spam Protection:
Enter the code shown: