Костыль
Доброго всем времени суток. Предлагаю костыль, реализующий механизм многопоточности (а точнее «многопроцессности») для WSH VBScript. Не рекомендуется лицам с аллергией на индокод.
Первая мысль о потенциальных удобствах многопоточности пришла однажды во время решения на добровольных началах относительно несложной задачи по обработке и визуализации информации. И, поскольку установка IDE навроде Visual Studio и наш Helpdesk — понятия несовместимые, из «легальных» оставались только VBA и WSH. В то время был выбран последний. А действующие административные ограничения и желание получить дружественные методы продиктовали требования к данной реализации многопроцессности:
- Код расположен в одном файле, как обычный сценарий.
- Использует минимум ActiveX, и только встроенных, работоспособен без WMI, под WSH x86/x64.
- Достаточная функциональность и удобство важнее быстродействия и паттернов.
Особенности:
- Запущенный скрипт выполняет служебную функцию. Основной код выполняется в последующих процессах.
- В «полной версии» основной код размещается только в классах, экземпляр любого из которых можно создать в отдельном процессе. В каждом новом процессе скрипт создает экземпляр служебного класса, который создает экземпляр указанного целевого класса, вызывает целевой метод, контролирует его ход, создает в глобальном контексте скриптов переменные, ссылающиеся на созданные экземпляры классов. В предшествующий скрипт возвращается объект инициализированного целевого класса, и «обрабатываются» события инициализации и завершения целевого класса запущенного скрипта.
- В «легкой версии» логика аналогична, только основной код размещается внутри sub’ов, предшествующему скрипту возвращается не объект, а индекс запущенного, и нет обработки событий.
- Для создания нового процесса скрипт рекурсивно запускает самого себя, передав данные о вызываемом методе и идентифицирующую информацию в именованном аргументе.
- Единого пространства исполнения нет, каждый скрипт хранит свои данные и объекты в своем контексте. Для обмена данными объект Me первого скрипта передается в последующие с применением GlobalContainer, описанным в теме «обмен данными и объектами между скриптами — 2» на Сером форуме. Каждый скрипт после завершения целевого метода ожидает разрешения на завершение, такая задержка позволяет забрать из него полученную информацию.
- Функционирует одинаково в WSH WScript и CScript, и в виде скомпилированного в ScriptCryptor exe-файла (правда, в exe не работают методы class_terminate).
Минусы:
- Сложность в отладке из-за использования во многих методах on error resume next и execute. Все ж таки это костыль.
- Громоздкость.
- Порядок завершения скриптов полностью в ответственности разработчика. Естественно, при обращении к объектам завершенного скрипта возникнет ошибка.
Актуально:
- Не реализованы мьютексы и механизмы залочивания метода от использования более чем одним процессом.
- Возможны сбои при одновременном доступе к переменным скрипта из контекстов других.
- Окно проводника остается в памяти при закрытии окна консоли CScript.exe.
Легкая версия mproclite.vbs:
option explicit
launch "base"
' main programm section
sub base()
startproc "msg"
startproc "msg"
startproc "msg"
msgbox "base, id = " & id, 64
free id
end sub
sub msg()
msgbox "msg, id = " & id, 64
free id
end sub
' do not modify service section
sub launch(byval destination)
dim job
executeglobal "dim scene, container, signature, subname, jobs, id, state, release"
release = false
if not wscript.arguments.named.exists("task") then
dim elt
executeglobal "dim found, lost"
id = 0
found = 0
lost = 0
signature = ""
randomize
do
signature = signature & hex(rnd * 16)
loop while len(signature) < 16
set scene = me
set jobs = createobject("Scripting.Dictionary")
set jobs(0) = scene
set container = getobject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
container.putproperty signature, scene
startproc destination
on error resume next
do until (lost >= found) or release
for elt = found to 1 step -1
if typename(jobs(elt)) = "Object" then
lost = lost + 1
jobs(elt) = empty
end if
err.clear
wscript.sleep 1
next
loop
release = true
executeglobal "scene_beforeterminate"
for elt = found to 1 step -1
if typename(jobs(elt)) = "VBScriptTypeInfo" then
jobs(elt).wscript.timeout = 1
jobs(elt).wscript.quit
err.clear
nojobs = false
end if
wscript.sleep 1
next
container.quit
else
job = split(wscript.arguments.named("task"), ";")
signature = cstr(job(0))
id = clng(job(1))
subname = cstr(job(2))
do
for each container in createobject("Shell.Application").windows
if isobject(container.getproperty(signature)) then
exit do
end if
next
wscript.sleep 1
loop
set scene = container.getproperty(signature)
set jobs = scene.jobs
state = 4
set jobs(id) = me
executeglobal subname
state = 24
do until release
wscript.sleep 10
loop
state = 28
end if
end sub
function startproc(subname)
startproc = createproc(subname)
joint startproc, 4, 0
REM do while getstate(startproc) < 4
REM wscript.sleep 10
REM loop
end function
function createproc(subname)
if me is scene then
if not release then
found = found + 1
createproc = found
set jobs(createproc) = nothing
createobject("WScript.Shell").exec("""" & wscript.fullname & """ """ & wscript.scriptfullname & """ ""/task:" & join(array(signature, createproc, subname), ";") & """")
end if
else
createproc = scene.createproc(subname)
end if
end function
function getjob(target)
on error resume next
if jobs.exists(target) then
set getjob = jobs(target)
if err.number = 0 then exit function
err.clear
end if
set getjob = nothing
end function
sub share(varname, value)
scene.newvar varname
if isobject(value) then
execute "set scene." & varname & " = value"
else
execute "scene." & varname & " = value"
end if
end sub
sub newvar(varname)
executecommand "dim " & varname
end sub
sub executecommand(command)
executeglobal command
end sub
function getstate(target)
dim elt
if jobs.exists(target) then
on error resume next
set elt = jobs(target)
getstate = elt.state
if err.number <> 0 then
if not(elt is nothing) then
getstate = 64
else
getstate = 1
end if
end if
set elt = nothing
else
getstate = 64
end if
end function
function isresponsive(target)
isresponsive = cbool(getstate(target) and 28)
end function
sub free(target)
if jobs.exists(target) then
on error resume next
jobs(target).release = true
else
dim elt, subname
for elt = scene.found to 1 step -1
on error resume next
subname = jobs(elt).subname
if subname = target then
free jobs(elt).id
end if
err.clear
next
end if
end sub
function joint(target, state, timeout)
dim reftime
reftime = timer
on error resume next
if jobs.exists(target) then
if isnumeric(target) then
do while getstate(target) < state
if timeisout(timeout, reftime) then
joint = false
exit function
end if
wscript.sleep 10
loop
else
dim elt, subname
for elt = scene.found to 1 step -1
subname = jobs(elt).subname
err.clear
if subname = target then
do while getstate(target) < state
if timeisout(timeout, reftime) then
joint = false
exit function
end if
wscript.sleep 10
loop
end if
err.clear
next
end if
end if
joint = true
end function
function timeisout(timeout, reftime)
if timeout > 0 then
dim delta
delta = timer - reftime
if delta < 0 then delta = delta + 86400
if delta > timeout then
timeisout = true
end if
else
timeisout = false
end if
end function
sub interrupt(target, timeout)
if jobs.exists(target) then
on error resume next
jobs(target).wscript.timeout = timeout
jobs(target).wscript.quit
else
dim elt, subname
for elt = scene.found to 1 step -1
on error resume next
subname = jobs(elt).subname
if subname = target then
interrupt jobs(elt).id
end if
err.clear
next
end if
end sub
sub push(name, value)
container.putproperty name, value
end sub
function pop(name)
on error resume next
if isobject(container.getproperty(name)) then
set pop = container.getproperty(name)
else
pop = container.getproperty(name)
end if
end function
Описание:
Функции механизма многопроцессности легкой версии:
launch subname
Запускает служебный алгоритм, выполнение скрипта всегда начинается с его вызова.
subname – строка, указывает целевой sub, который будет выполнен в новом процессе.
Аргументы этого метода используются только в первично запущенном скрипте для начала выполнения основного кода.
В каждом новом скрипте:
- Объявляются переменные в глобальном пространстве запущенного скрипта:
scene – ссылка на объект Me первого скрипта,
container – ссылка на окно проводника GlobalContainer,
signature – строка, сгенерирована для идентификации GlobalContainer,
found, lost – только для scene – счетчики созданных и завершенных процессов скриптов,
subname – строка, содержит цель скрипта,
jobs – ссылка на словарь с объектами Me запущенных скриптов, созданный в scene,
id – порядковый номер данного скрипта — ключ в словаре,
release = Ложь — после завершения целевого sub’а скрипт будет завершен после присвоения Истина,
state = 4 – состояние, в котором находится данный скрипт. - Добавляется элемент в словарь jobs.
startproc(subname)
subname – см. launch().
Создает новый процесс скрипта, ожидает его готовности до состояния 4 (см. getstate()), когда можно обращаться к объекту Me скрипта. Возвращает число — id запущенного скрипта.
createproc(subname)
subname – см. launch().
Создает новый процесс скрипта, не ожидая, возвращает число — id запущенного скрипта. Используется для асинхронного создания нескольких процессов в цикле, без ожидания готовности каждого. Заметно быстрее по сравнению с использованием startproc() для такого применения.
getjob(target)
target – число, id скрипта или строка, имя subname группы созданных скриптов.
Обеспечивает доступ к объекту Me скрипта. Возвращает ссылку на объект Me скрипта, если id не найден или скрипт завершен – Nothing.
getstate(target)
target – число, id скрипта.
Определяет состояние скрипта. Возвращает число, этап выполнения:
1 процесс создан (new process exec),
4 скрипт запущен (initialized),
24 целевой sub выполнен (sub completed),
28 скрипт освобожден (released),
64 не найден (host not found), скрипт завершен (terminated).
isresponsive(target)
target — см. getstate().
Определяет доступность объекта Me скрипта (состояния с 4 по 28). Возвращает булево значение.
executecommand command
command — строка, содержащая инструкции.
Вызов интерпретатора для выполнения операторов в глобальном пространстве скрипта.
share varname, value
varname — строка, содержащая имя переменной, value – любое значение.
Объявляет в глобальном пространстве первого скрипта переменную с именем varname, которая становится доступна всем скриптам в виде свойства scene, присваивает переменной содержимое value.
newvar varname
varname — строка, содержащая имя переменной.
Объявляет новую переменную в глобальном пространстве скрипта.
free target
target – число, id скрипта или строка, имя subname группы созданных скриптов. Разрешает завершение скрипта после выполнения целевого sub’а. Работает с одним скриптом или с группой.
joint(target, state, timeout)
target — см. free(), state — см. getstate(), timeout – число, в секундах, с миллисекундами.
Ожидает наступления состояния скрипта state, для группы скриптов ожидание длится, пока каждый не достигнет state. Ожидание ограничено таймаутом, timeout = 0 означает неограниченное ожидание. Возвращает булево значение, Истина – ожидание закончено, Ложь – таймаут. Предназначен для синхронизации работы скриптов. Например, если необходимо дождаться запуска скрипта — 4, полного завершения скрипта — 64;
interrupt target, timeout
target — см. free(), timeout – значение для wscript.timeout, в секундах.
Переводит скрипт к штатному завершению, с выполнением методов class_terminate. Если в скрипте были открыты диалоговые окна, он перейдет к завершению только после паузы timeout. Повторное появление диалогового окна в методах class_terminate остановит завершение.
push name, value
name – строка, имя свойства, value – любое значение.
Помещает в свойство GlobalContainer с именем name содержимое value.
pop(name)
name – строка, имя свойства.
Возвращает из GlobalContainer содержимое свойства с именем name.
Полная версия mproc.vbs:
option explicit
dim mproc
set mproc = new multiprocess
mproc.launch "base", "run", ""
' main programm section
class base
public sub run()
host.startproc "msg", "run", "first"
host.startproc "msg", "run", "second"
host.startproc "msg", "run", "third"
msgbox "base, id = " & host.id, 64
host.free host.id
end sub
end class
class msg
public sub run()
msgbox host.aliasname & ", id = " & host.id, 64
host.free host.id
end sub
end class
' do not modify service class section
class multiprocess
public primary, ancestor, parent, process, err
public names, execs, hosts
public id, aid, isprimary
public classname, methodname, aliasname
public found, lost, active
public state, permit, release
private container, signature, wshshell
public sub launch(startclassname, startmethodname, startaliasname)
permit = false
release = false
executeglobal "dim scene, host, ancestor, process"
if not isempty(host) then exit sub
set host = me
executeglobal "set host.err = err"
executeglobal "function getroot: set getroot = me: end function"
set parent = getroot
isprimary = not wscript.arguments.named.exists("task")
if isprimary then
dim sample
state = 24
randomize
signature = ""
do
signature = signature & hex(rnd * 16)
loop while len(signature) < 16
aid = empty
id = 0
found = 0
lost = 0
set wshshell = createobject("WScript.Shell")
set primary = host
set ancestor = nothing
set process = nothing
set scene = parent
set parent.ancestor = nothing
set parent.process = nothing
set hosts = createobject("Scripting.Dictionary")
set execs = createobject("Scripting.Dictionary")
set names = createobject("Scripting.Dictionary")
classname = empty
methodname = empty
aliasname = empty
set hosts(0) = host
set container = getobject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
container.putproperty signature, parent
startproc startclassname, startmethodname, startaliasname
on error resume next
do
for each sample in execs.keys
if release or active = 0 then exit do
if not (execs(sample) is nothing) then
if execs(sample).status > 0 then
abolish sample
end if
end if
wscript.sleep 1
next
loop
release = true
state = 28
scenequit
else
dim job
job = split(wscript.arguments.named("task"), ";")
signature = cstr(job(0))
do
for each container in createobject("Shell.Application").windows
if isobject(container.getproperty(signature)) then
exit do
end if
next
wscript.sleep 1
loop
aid = clng(job(1))
id = clng(job(2))
found = null
lost = null
set scene = container.getproperty(signature)
set primary = scene.host
set hosts = primary.hosts
set ancestor = hosts(aid)
if isresponsive(aid) then
set parent.ancestor = ancestor.parent.process
else
set parent.ancestor = nothing
end if
classname = cstr(job(3))
methodname = cstr(job(4))
aliasname = cstr(job(5))
state = 4
primary.implicate id, aliasname, host
executeglobal "set process = new " & classname
executeglobal "set host.process = process"
executeglobal "set scene." & aliasname & " = process"
if isresponsive(aid) then
executeglobal "set host.ancestor.parent." & aliasname & " = process"
end if
state = 8
primary.staff host
ancestorevent "oninitialized"
state = 12
if methodname <> "" then
do until permit
wscript.sleep 10
loop
state = 16
executeglobal "process." & methodname
end if
state = 20
ancestorevent "oncompleted"
state = 24
do until release
wscript.sleep 10
loop
state = 28
end if
end sub
public default function startproc(classname, methodname, aliasname)
set startproc = start(createproc(classname, methodname, aliasname))
end function
public function createproc(classname, methodname, aliasname)
if aliasname = "" then aliasname = classname
newvar aliasname
scene.host.newvar aliasname
createproc = primary.spawn(id, classname, methodname, aliasname)
end function
public function spawn(issuer, classname, methodname, aliasname)
if not release then
found = found + 1
spawn = found
active = found - lost
names(spawn) = aliasname
set hosts(spawn) = nothing
if not hosts.exists(aliasname) then
hosts.add aliasname, createobject("Scripting.Dictionary")
end if
set hosts(aliasname)(spawn) = nothing
execs.add spawn, wshshell.exec("""" & wscript.fullname & """ """ & wscript.scriptfullname & """ ""/task:" & join(array(signature, issuer, spawn, classname, methodname, aliasname), ";") & """")
end if
end function
public function start(target)
select case outline(target)
case "Nothing", "multiprocess"
do while getstate(target) < 12
wscript.sleep 10
loop
if isresponsive(target) then
set start = hosts(target).process
hosts(target).permit = true
else
set start = nothing
end if
case "Dictionary"
dim elt
set start = hosts(target)
for each elt in start.keys
do while getstate(elt) < 12
wscript.sleep 10
loop
next
for each elt in start.keys
if isresponsive(elt) then
hosts(elt).permit = true
end if
next
case else
set start = nothing
end select
end function
public sub implicate(id, aliasname, host)
set hosts(aliasname)(id) = host
set hosts(id) = host
end sub
public sub staff(host)
set hosts(host.process) = host
end sub
public sub abolish(id)
if hosts.exists(names(id)) then
hosts(names(id))(id) = empty
end if
names(id) = empty
if isresponsive(id) then
hosts(hosts(id).process) = empty
end if
hosts(id) = empty
set execs(id) = nothing
lost = lost + 1
active = found - lost
end sub
private sub ancestorevent(eventname)
if aid > 0 then
on error resume next
executeglobal "ancestor." & aliasname & "_" & eventname & " host.hosts(" & id & ")"
if err.number = 424 or err.number = 438 then err.clear
end if
end sub
public sub assignhandler(handlername, byval varsqty)
dim vars
vars = ""
if varsqty > 0 then
do
vars = vars & "param" & varsqty
varsqty = varsqty - 1
if varsqty = 0 then exit do
vars = vars & ", "
loop
end if
executeglobal "sub " & handlername & "(" & vars & "): process." & handlername & " " & vars & ": end sub"
end sub
public sub newvar(varname)
executecommand "dim " & varname
end sub
public sub executecommand(command)
executeglobal command
end sub
public function getstate(target)
select case outline(target)
case "multiprocess"
on error resume next
getstate = hosts(target).state
if err.number <> 0 then
err.clear
getstate = 64
end if
case "Nothing"
getstate = 1
case "Dictionary"
getstate = null
case empty
getstate = 0
case else
getstate = 64
end select
end function
private function outline(target)
on error resume next
if hosts.exists(target) then
outline = typename(hosts(target))
if err.number <> 0 then
err.clear
outline = "Object"
end if
else
outline = empty
end if
end function
public function isresponsive(target)
isresponsive = cbool(getstate(target) and 28)
end function
public function getid(target)
on error resume next
if isobject(target) then
if isresponsive(target) then
getid = hosts(target).id
if err.number = 0 then exit function
err.clear
end if
elseif primary.execs.exists(target) then
getid = target
exit function
end if
getid = null
end function
public function gethost(target)
on error resume next
if hosts.exists(target) then
set gethost = hosts(target)
if err.number = 0 then exit function
err.clear
end if
set gethost = nothing
end function
public sub free(target)
select case outline(target)
case "multiprocess"
on error resume next
gethost(target).release = true
err.clear
case "Dictionary"
dim elt
for each elt in gethost(target)
free(elt)
next
end select
end sub
public function joint(target, state, timeout)
dim reftime
reftime = timer
select case outline(target)
case "multiprocess", "Nothing"
do while getstate(target) < state
if timeisout(timeout, reftime) then
joint = false
exit function
end if
wscript.sleep 10
loop
case "Dictionary"
dim elt
for each elt in gethost(target)
do while getstate(elt) < state
if timeisout(timeout, reftime) then
joint = false
exit function
end if
wscript.sleep 10
loop
next
end select
joint = true
end function
private function timeisout(timeout, reftime)
if timeout > 0 then
dim delta
delta = timer - reftime
if delta < 0 then delta = delta + 86400
if delta > timeout then
timeisout = true
end if
else
timeisout = false
end if
end function
public sub interrupt(target, timeout)
select case outline(target)
case "multiprocess"
on error resume next
with gethost(target).parent
.wscript.timeout = timeout
.wscript.quit
end with
err.clear
case "Dictionary"
dim elt
for each elt in gethost(target)
interrupt elt, timeout
next
end select
end sub
public sub kickout(target)
if primary.execs.exists(target) then
if getstate(target) < 64 then
on error resume next
primary.execs(target).terminate
err.clear
end if
else
select case outline(target)
case "multiprocess"
kickout getid(target)
case "Dictionary"
dim elt
for each elt in gethost(target)
kickout(elt)
next
end select
end if
end sub
public sub terminate(target)
interrupt target, 1
if not joint(target, 64, 2) then kickout target
end sub
public sub push(name, value)
container.putproperty name, value
end sub
public function pop(name)
on error resume next
if isobject(container.getproperty(name)) then
set pop = container.getproperty(name)
else
pop = container.getproperty(name)
end if
end function
private sub scenequit
if isprimary then
dim col, i, status
col = execs.keys
for i = ubound(col) to 0 step -1
interrupt col(i), 1
next
wscript.sleep 2000
on error resume next
for i = ubound(col) to 0 step -1
status = execs(col(i)).status
if err.number = 0 and status = 0 then execs(col(i)).terminate
err.clear
next
container.quit
end if
end sub
private sub class_terminate()
if state < 28 and isprimary then scenequit
end sub
end class
Описание:
Методы класса multiprocess:
launch classname, methodname, aliasname
Запускает служебный алгоритм, выполнение скрипта всегда начинается с его вызова.
classname, methodname, aliasname – строки. Указывают целевой класс classname и метод этого класса methodname, который будет выполнен в новом процессе, экземпляр класса classname будет помещен в переменную с именем aliasname (или classname, если aliasname – пустая строка).
Аргументы этого метода используются только в первично запущенном скрипте для начала выполнения основного кода.
В каждом новом скрипте:
- Объявляются переменные в глобальном пространстве запущенного скрипта:
scene – ссылка на объект Me первого скрипта,
host – экземпляр класса multiprocess данного скрипта,
process – экземпляр целевого класса с именем classname, которое было указано предшествующим скриптом при создании процесса данного скрипта,
ancestor – экземпляр целевого класса предшествующего скрипта. - Объявляются переменные в глобальном пространстве scene и предшествующего скрипта, с именем aliasname – ссылки на экземпляр целевого класса данного скрипта.
- Задаются свойства host:
primary – ссылка на экземпляр класса multiprocess первого скрипта,
ancestor – ссылка на экземпляр класса multiprocess предшествующего скрипта,
parent – объект Me данного скрипта,
process – ссылка на process в глобальном пространстве,
err – ссылка на объект err данного скрипта,
names – ссылка на словарь с aliasname, созданный в primary,
execs – ссылка на словарь с объектами wshexec запущенных процессов, созданный в primary,
hosts – ссылка на словарь с объектами host запущенных процессов, созданный primary,
id – порядковый номер данного скрипта — ключ в словарях,
aid – то же, предшествующего скрипта,
isprimary – булево, является ли данный скрипт первично запущенным,
found, lost, active – только для primary – счетчики созданных, завершенных и активных процессов скриптов,
classname, methodname, aliasname – содержат цель скрипта,
permit = Ложь — целевой метод будет запущен после присвоения Истина,
release = Ложь — после завершения целевого метода скрипт будет завершен после присвоения Истина,
state = 4 – состояние, в котором находится данный скрипт. - Добавляются элементы в словари names, execs, hosts.
startproc(classname, methodname, aliasname)
classname, methodname, aliasname – см. launch().
Создает новый процесс скрипта, ожидает его готовности до состояния 12 (см. getstate()), запускает целевой метод. Возвращает ссылку на инициализированный в новом процессе экземпляр целевого класса.
createproc(classname, methodname, aliasname)
classname, methodname, aliasname – см. launch().
Создает новый процесс скрипта, не ожидая, возвращает его id. Используется для асинхронного создания нескольких процессов в цикле, без ожидания готовности каждого. Заметно быстрее по сравнению с использованием startproc() для такого применения.
start(target)
target – число, id скрипта, или строка, имя aliasname группы созданных скриптов.
Ожидает готовности скрипта, созданного с использованием createproc(), до состояния 12, разрешает выполнение целевого метода. Возможно использование для группы скриптов, имеющих одинаковый aliasname. Для одного скрипта возвращает ссылку на его инициализированный в новом процессе экземпляр целевого класса, для группы скриптов возвращает ссылку на субсловарь, содержащий все host с данными aliasname.
gethost(target)
target – число, id скрипта или строка, имя aliasname группы созданных скриптов, или объект process скрипта.
Обеспечивает доступ к экземпляру host класса multiprocess требуемого скрипта. Для одного скрипта возвращает ссылку на его host, для группы скриптов возвращает ссылку на субсловарь, содержащий все host с данными aliasname, если id не найден или скрипт завершен – Nothing.
getid(target)
target – число, id скрипта, или объект process скрипта.
Возвращает id срипта, определенное по объекту process. Только для действующих скриптов.
getstate(target)
target — см. getid().
Определяет состояние скрипта. Возвращает число, этап выполнения:
0 не найден (host not found),
1 процесс создан (new process exec),
4 host инициализирован (host initialized),
8 целевой класс инициализирован (process initialized),
12 целевой класс инициализирован, событие обработано (process initialized handled),
16 целевой метод запущен (process method launched),
20 целевой метод выполнен (process completed),
24 целевой метод выполнен, событие обработано (process completed handled),
28 скрипт освобожден (released),
64 скрипт завершен (terminated).
isresponsive(target)
target — см. getid().
Определяет доступность объекта host скрипта (состояния с 4 по 28). Возвращает булево значение.
assignhandler handlername, varsqty
handlername — строка, имя события, varsqty — число, количество передаваемых аргументов.
Создает в глобальном пространстве хэндлер события sub с именем события handlername, связывет его с одноименным методом в созданном объекте process. При наступлении события, хэндлер перенаправит вызов в process. handlername().
executecommand command
command — строка, содержащая инструкции.
Вызов интерпретатора для выполнения операторов в глобальном пространстве скрипта.
newvar varname
varname — строка, содержащая имя переменной.
Объявляет новую переменную в глобальном пространстве скрипта.
free target
target — см. gethost().
Разрешает завершение скрипта после выполнения целевого метода. Работает с одним скриптом или с группой.
joint(target, state, timeout)
target — см. gethost(), state — см. getstate(), timeout – число, в секундах, с миллисекундами.
Ожидает наступления состояния скрипта state, для группы скриптов ожидание длится, пока каждый не достигнет state. Ожидание ограничено таймаутом, timeout = 0 означает неограниченное ожидание. Возвращает булево значение, Истина – ожидание закончено, Ложь – таймаут. Предназначен для синхронизации работы скриптов. Например, если необходимо дождаться создания объекта process — 8, полного завершения скрипта — 64;
interrupt target, timeout
target — см. gethost(), timeout – значение для wscript.timeout, в секундах.
Переводит скрипт к штатному завершению, с выполнением методов class_terminate. Если в скрипте были открыты диалоговые окна, он перейдет к завершению только после паузы timeout. Повторное появление диалогового окна в методах class_terminate остановит завершение.
kickout target
target — см. gethost().
Завершает процесс скрипта на уровне ОС, используя wshexec.terminate. Возможно длительное выполнение, до 2 сек для каждого скрипта. Работает с одним скриптом или с группой.
terminate target
target — см. gethost().
Завершает скрипт, использует сначала interrupt, затем при необходимости kickout.
push name, value
name – строка, имя свойства, value – любое значение.
Помещает в свойство GlobalContainer с именем name содержимое value.
pop(name)
name – строка, имя свойства.
Возвращает из GlobalContainer содержимое свойства с именем name.
Методы, которые можно разместить в целевом классе данного скрипта в качестве хэндлеров событий инициализации целевого класса и выполнения целевого метода запущенного скрипта:
<aliasname>_ oninitialized(source)
source – передаваемый в метод объект host скрипта, вызвавшего метод, его aliasname содержится в имени метода. Метод вызывается после инициализации целевого класса запущенного скрипта (state = 8).
<aliasname>_ oncompleted(source)
source — передаваемый в метод объект host скрипта, вызвавшего метод, его aliasname содержится в имени метода. Метод вызывается после выполнения целевого метода запущенного скрипта (state = 20).
Пример:
Для mproclite и mproc демонстрируется работа на примере абстрактной задачи: для каждого символа из строки letters создаются отдельные процессы, каждый в цикле помещает свой символ в буфер, по мере заполнения которого другой процесс выводит по 3 «слова» в консоль. Для WScript консоль сымитирована окном IE. Попутно выводятся запущенные и остановленные процессы ОС (в примере используется WMI, но для функционирования механизма он не обязателен).
В ходе дебага у меня накопились некоторые наблюдения и комменты, коими я поделюсь, если будет спрос — дело в том, что потребуется время, чтобы привести их в читабельный вид. Конструктивная критика приветствуется.