Костыль
Доброго всем времени суток. Предлагаю костыль, реализующий механизм многопоточности (а точнее «многопроцессности») для 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, но для функционирования механизма он не обязателен).
В ходе дебага у меня накопились некоторые наблюдения и комменты, коими я поделюсь, если будет спрос — дело в том, что потребуется время, чтобы привести их в читабельный вид. Конструктивная критика приветствуется.
ссылка на оригинал статьи http://habrahabr.ru/post/189786/
Добавить комментарий