3
Сентября, 2001
Владимир Трухин
ведущий инженер-программист
ОАО "Воткинская ГЭС"
Fax: +7 (34241) 63297
E-mail: vlt@gesvt.permenergo.ru
vlt@votges.ru
Дистанционная
выгрузка приложений
Проблема
Приложения
создаются для пользователей и
запускаются пользователями.
Будучи запущенным пользователем,
приложение может работать с утра
и до вечера. Пользователь в это
время может беззаботно уйти
обедать или совещаться в смежный
отдел.
Но вот
незадача, именно в это самое время
Вам, как администратору системы
или как разработчику, необходимо
изменить структуры таблиц или
выполнить срочные работы на
сервере. Как быть с работающим
приложением? Сбросить соединение
пользователя или отключить
сервер, несмотря на работающее
приложение? Это может привести к
потере данных. Дождаться
появления пользователя? Но от
этого могут пострадать другие
клиенты, ожидающие завершения
работ. Сбегать самому и выгрузить
программу? Хорошая идея, если для
этого не надо преодолевать
десятки миль. Извечный вопрос: «Что
делать?».
Решение
Решение
как всегда очевидно. Нужно
обеспечить механизм отправки
команды администратором,
получения этой команды
приложением и отработки
завершения.
Нет,
это не моя оригинальная идея. Вы
могли читать о том, что
администратору достаточно
разместить в некотором каталоге
некоторый файл, а приложению
обнаружить этот файл и
завершиться без участия
пользователя.
Всё
это было бы очень хорошо, если бы
не следующие моменты:
· Каждое приложение имеет
свою специфику и должно
выгружаться особенным для него
способом. Как сделать так, чтобы в
рамках одного класса обеспечить
настройку завершения конкретного
приложения?
· Система может состоять из
некоторого числа связанных или
несвязанных приложений, поэтому
должна существовать возможность
выгрузки выбранного приложения
или всех приложений разом.
· Приложения не должны
внезапно исчезать с экрана.
· Пользователь должен
получить сообщение о причинах
выгрузки приложения или
предполагаемом времени
возобновления работы.
· Пользователь должен иметь
отсрочку выгрузки приложения,
чтобы успеть произвести ручную
выгрузку приложения так, как он
это делает обычно. При этом он
должен видеть, сколько времени
осталось до автоматического
завершения.
Для реализации этих
требований средство
автоматической выгрузки
приложения должно обладать
следующими возможностями:
· Объект класса
автоматической выгрузки
приложения должен быть невидимым
до получения команды выгрузки
приложения.
·
Объект класса должен
реагировать на два события:
1.
Появление в каталоге файла,
являющегося командой выгрузки
этого приложения.
2.
Появление в каталоге файла,
являющегося командой выгрузки
всех приложений.
· Объект класса должен
хранить ссылку на процедуру
завершения приложения,
имитирующую действия
пользователя по завершению
приложения.
· При получении команды
выгрузки приложения объект
класса должен стать видимым.
· Командный файл должен
содержать текст сообщения,
которое считывается объектом
класса и показывается
пользователю.
· На экземпляре класса
должен располагаться индикатор
прогрессии, показывающий время,
оставшееся до полного завершения
приложения.
· По истечении времени
ожидания действий пользователя,
экземпляр класса должен
запустить процедуру завершения
приложения.
· Экземпляр класса должен
работать как в приложении с
главным окном, так и в приложении
без главного окна.
Индикатор прогрессии
В
качестве индикатора прогрессии
можно использовать любой
имеющийся класс индикатора
процесса или элемент ActiveX.
Предположим, что у нас нет ни того,
ни другого. Создать индикатор
процесса совсем не трудно.
Достаточно использовать
контейнер, как базовый класс, и
разместить в нём объекты
изображающие индикатор. Это могут
быть объекты класса SHAPE. Первый будет показывать общую длину
процесса, другой текущее значение
процесса.
Определение такого
класса может выглядеть следующим
образом:
DEFINE
CLASS progressbar AS container
** Длина полосы индикатора
Width
= 100
** Высота полосы индикатора
Height
= 20
BackStyle
= 0
BorderWidth
= 0
**
Максимальное значение переменной
процесса
MaxValue
= (this.Width)
**
Текущее значение переменной
процесса
CurrentValue
= 0
Name
= "progressbar"
**
Объект, показывающий общую длину
процесса
ADD OBJECT border AS shape WITH ;
** Разместить на всей площади контейнера
Top = 0, ;
Left = 0, ;
Height = (this.parent.Height), ;
Width = (this.parent.Width), ;
Name = "Border"
ADD
OBJECT bar AS shape WITH
;
**
Разместить по высоте контейнера с
нулевой длиной
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
** При изменении текущего
значения параметра
** необходимо перерисовать
объект текущего значения
LPARAMETERS
vNewVal
** Анализ значения принятого
параметра
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
перерисовка объекта
THIS.Bar.Width=int(THIS.Width*(THIS.CurrentValue/THIS.MaxValue))
ENDPROC
PROCEDURE
Init
**
Настройка объектов на размер
контейнера
this.Bar.Height=this.Height
this.Bar.Width=0
this.Border.Height=this.Height
this.Border.Width=this.Width
ENDPROC
ENDDEFINE
Окно оповещения пользователя
Окно
оповещения пользователя будет
появляться на экране после
обнаружения команды выгрузки
приложения. На этом окне
размешается индикатор прогресса,
текст извещения для пользователя
и мигающий красный индикатор,
который можно использовать для
привлечения внимания
пользователя.
После
появления этого окна на экране,
должен запуститься индикатор
процесса. Когда индикатор
достигнет своего граничного
значения, должна запуститься
процедура завершения приложения.
Примерный
код для этого класса:
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
= "Attantion! “+;
“This
application will have been shutdowned. “+;
“Save data and exit!", ;
Height
= 33, ;
Left =
26, ;
Top =
5, ;
Width
= 265, ;
Name =
"Label1"
** Изображение включенного индикатора
ADD OBJECT lighton AS image WITH ;
Picture
= "red.bmp", ;
BackStyle
= 0, ;
Height
= 12, ;
Left =
11, ;
Top =
8, ;
Width
= 12, ;
Name =
"LightOn"
** Изображение отключенного индикатора
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"
** Таймер времени ожидания пользователя
ADD OBJECT timer AS timer WITH ;
Top =
11, ;
Left =
270, ;
Height
= 23, ;
Width
= 23, ;
Enabled
= .F., ;
Interval
= 500, ;
Name =
"Timer"
** Объект индикатора процесса
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 getcaption
if type('gcVersion')='C'
return allt(gcVersion)
else
return 'Attention'
endif
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 have been unload to update it!'
ENDPROC
ENDDEFINE
Окно оповещения пользователя в
приложении на базе формы верхнего
уровня
Определим
подкласс для класса окна
оповещения пользователя. Цель
этого подкласса – работа в
приложении на базе формы верхнего
уровня без главного окна Visual FoxPro.
DEFINE
CLASS alarmwindowtlf AS alarmwindow
Desktop = .F.
ShowWindow = 1
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
Класс дистанционной выгрузки
приложения
Определим
класс дистанционной выгрузки
приложения. Именно он должен
невидимо работать всё время
существования приложения,
обнаруживать командные файлы,
запускать окно оповещения
пользователя и в случае
необходимости самостоятельно
выгружать приложение.
DEFINE
CLASS powershutdownms AS timer
Height = 23
Width = 23
Enabled = .F.
**
Интервал поиска файла (по
умолчанию)
Interval
= 60000
**
Имя файла для выгрузки всех
приложений
systemshutdownfile
= "ShutDown.txt"
** Имя файла для выгрузки
конкретного приложения
taskshutdownfile
= NULL
** Время ожидания действий
пользователя
shutdownwaittime
= 180000
** Имя процедуры завершения
приложения
shutdownhandler
= NULL
PROTECTED alarmmess
alarmmess = NULL
Name = "powershutdownms"
PROTECTED inform
** Запуск окна оповещения
пользователя
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
**
Обработка события завершения
ожидания пользователя
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
**
Завершение приложения (по
умолчанию)
PROCEDURE
shutdown
quit
ENDPROC
**
Поиск командного файла
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
Подкласс класса дистанционной
выгрузки приложения для работы
без главного окна VFP
Этот
подкласс будет отличаться от
своего родителя только кодом
метода запуска окна оповещения
пользователя – StartAlarm.
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
Заключение
Разместив код для
создания объекта этого класса в MAIN-модуле
приложения, мы обеспечим
дистанционную выгрузку
приложения и развяжем себе руки.
Пример такого кода
может выглядеть следующим
образом:
**
MAIN
PROCEDURE MAIN
PUBLIC goPSD
SET CLASSLIB TO SHUTDOWN
goPSD=createobject(‘PowerShutDownMS’)
** Интервал для поиска командного
файла = 3 минут
goPSD.Interval=3*60*1000
** Время ожидания действий
пользователя = 5 минут
goPSD.ShutDownWaitTime=5*60*1000
** Процедура завершения
goPSD.ShutDownHandler=’Finish’
goPSD.Enabled=.T.
** …
** код инициализации приложения
** …
ENDPROC
PROCEDURE Finish
** код завершения приложения
ENDPROC
Демонстрационный
пример и текст статьи в формате MS
Word (zip-файл,65KB)
Главная
страница | Технологии | Продукция | Материалы | Специалисты | Партнёры
Запись
в Гостевую Книгу |
Просмотр Гостевой Книги
|