1 (изменено: Xameleon, 2017-01-17 19:43:15)

Тема: WSH: обмен данными и объектами между скриптами — 2

Доброго времени суток господа. Да, уже неоднократно эта тема поднималась и обсуждалась. Согласен. Но я решил предложить Вашему вниманию более простой, на мой взгляд, способ обмена.

Преимущества:
1) Можно обмениваться любыми типами данных (доступных скриптам) между процессами. В том числе и объектами.
2) Отсутствие надобности создавать лишние процессы.
3) Всё делается встроенными средствами Windows. Не нужны посторонние Activex.

Обмен данными осуществляется через экземпляр класса - GlobalContainer.
Для начала используется метод Open("name"), чтобы открыть уже готовый либо создать новый контейнер, в котором будут храниться данные.
Это позволит использовать независимые хранилища для разных приложений.
Для передачи и получения данных используются соответсвенно 2 метода PutProperty(name,value) и GetProperty(name).
Ниже приведён пример из 2-ух vbs скриптов. В каждом из которых присутствует класс.
Первым запускается 1.vbs. Вторым 2.vbs.

Во второй скрипт, в качестве примера, передаётся значение введённое пользователем + созданный в первом скрипте объект Scripting.FileSystemObject.

Отдаю на тестирование. Интересно - как будет работать у Вас.

1.vbs

Dim gCon, fso
Set gCon = New GlobalContainer
gCon.Open "storage"
gCon.PutProperty "test",InputBox("Введите значение для глобальной переменной ""test"".")
set fso = CreateObject("Scripting.FileSystemObject")
gCon.PutProperty "fso",fso

MsgBox "Значение переменных установлено. Запустите второй скрипт, не закрывая окна."

Class GlobalContainer
    Private wnd, owner
    Sub Open(name)
        For Each wnd in CreateObject("Shell.Application").Windows
            if Instr(1,wnd.GetProperty("container_name"),name) = 1 Then Exit Sub
        Next
        owner = True
        Set wnd = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        wnd.PutProperty "container_name", name
    End Sub
    
    Sub PutProperty(name, value)    
        wnd.PutProperty name, value
    End Sub
    
    Function GetProperty(name)
        On Error Resume Next
        if IsObject(wnd.GetProperty(name)) Then
            Set GetProperty = wnd.GetProperty(name)
        Else
            GetProperty = wnd.GetProperty(name)
        End if
    End Function

    Private Sub Class_Terminate()
        On Error Resume Next
        if owner Then wnd.Quit()
    End Sub
End Class

2.vbs

Dim gCon
Set gCon = New GlobalContainer
gCon.Open "storage"
MsgBox "Значение переменной ""test"": " & gCon.GetProperty("test") ,vbInformation
MsgBox "Тип переменной ""fso"": " & TypeName(gCon.GetProperty("fso")),vbInformation

Class GlobalContainer
    Private wnd, owner
    Sub Open(name)
        For Each wnd in CreateObject("Shell.Application").Windows
            if Instr(1,wnd.GetProperty("container_name"),name) = 1 Then Exit Sub
        Next
        owner = True
        Set wnd = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        wnd.PutProperty "container_name", name
    End Sub
    
    Sub PutProperty(name, value)    
        wnd.PutProperty name, value
    End Sub
    
    Function GetProperty(name)
        On Error Resume Next
        if IsObject(wnd.GetProperty(name)) Then
            Set GetProperty = wnd.GetProperty(name)
        Else
            GetProperty = wnd.GetProperty(name)
        End if
    End Function

    Private Sub Class_Terminate()
        On Error Resume Next
        if owner Then wnd.Quit()
    End Sub
End Class

23.09.2011: (!) Обнаружена и исправлена ошибка при выгрузке класса. Экземпляр окна оставался в памяти после выгрузки.

20.04.2013: (!) Метод поиска контейнера изменён. Теперь поиск осуществляется по устанавливаемому Property "container_name".

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

2

Re: WSH: обмен данными и объектами между скриптами — 2

Прошу в заголовке проставить скриптовый язык для тех, кто не в теме.

3

Re: WSH: обмен данными и объектами между скриптами — 2

Виноват. Давно на форум не заглядывал.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

4

Re: WSH: обмен данными и объектами между скриптами — 2

Интересный способ

5

Re: WSH: обмен данными и объектами между скриптами — 2

Сам не ожидал. ) Как ни странно - создаваемый объект {C08AFD90-F2A1-11D1-8455-00A0C91F3880} кроме всего прочего имеет действующий hWnd, что в принципе тоже можно попользовать. )

2 all & VSVLAD: Скрипт нормально пашет ? Сбоев нет ? Интересует на чём проверенно. Т.к предположительно на разных ОС может давать разный результат. Я пока проверил на XP и Windows 7 Ultimate x64.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

6 (изменено: VSVLAD, 2011-03-09 22:07:36)

Re: WSH: обмен данными и объектами между скриптами — 2

Я как понял класс создаёт экземпляр WebBrowser, а внутри него имеются методы для записи и чтения свойств.
Проверял на: XP Professional SP3, IE8.0.6001 - всё Окей

--
Проверил поиском по реестру в поисках этого CLSID - и не нашлось. Магия

7 (изменено: Xameleon, 2011-03-09 22:09:00)

Re: WSH: обмен данными и объектами между скриптами — 2

Обнаружил интересную, но вполне логичную особенность. Объект хранит в себе данные, даже после завершения всех скриптов. Практически как буфер обмена. По крайней мере на Windows 7 Ultimate так происходит. Не заметил - есть ли этот эффект на XP.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

8 (изменено: Xameleon, 2011-03-09 22:13:16)

Re: WSH: обмен данными и объектами между скриптами — 2

VSVLAD пишет:

Я как понял класс создаёт экземпляр WebBrowser, а внутри него имеются методы для записи и чтения свойств.
Проверял на: XP Professional SP3, IE8.0.6001 - всё Окей

--
Проверил поиском по реестру в поисках этого CLSID - и не нашлось. Магия

Магия ) Она самая. Только что и я проверил. Действительно его нет в реестре. Видимо это чудо ))). Ну ладно. Не буду раскрывать всех фокусов . А то эффект пропадёт )).

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

9 (изменено: Евген, 2011-03-25 15:27:23)

Re: WSH: обмен данными и объектами между скриптами — 2

Судя по всему этот CLSID не прописанный в реестре ниукого, как-то очень похож на объект IE. Сегодня нагуглил перечисление глаголов этого объекта, вот код

Option Explicit
Class Class1
Dim objIE,Verb

Sub Class_Initialize
Set objIE=GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
objIE.Navigate2 0
Do While objIE.Busy Or objIE.ReadyState<>4
  WScript.Sleep 100
Loop
For Each Verb In objIE.Document.Application.NameSpace(strPath).Self.Verbs
Wscript.Echo Verb.Name
Next 
objIE.Quit 
End Sub

Sub Class_Terminate
On Error Resume Next
objIE.Quit
End Sub
End Class

Dim x,strPath

strPath="c:\util"

Set x=New Class1
Времени не хватает... :-(

10

Re: WSH: обмен данными и объектами между скриптами — 2

Следующий код

var x = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}");
WScript.Echo(x);

отзывается так:

Microsoft Internet Explorer

( 2 * b ) || ! ( 2 * b )

11

Re: WSH: обмен данными и объектами между скриптами — 2

Я думаю этот CLSID принадлежит ActiveX компоненту WebBrowser, который также как ActiveX компонент Internet Explorer находятся в библиотеке shdocvw.dll, а начиная с IE 7 перенеслись в ieframe.dll

12 (изменено: Евген, 2011-03-10 11:50:12)

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata пишет:

отзывается так:

Microsoft Internet Explorer

Windows 7 Ultimate x64
отзывается как

Проводник Windows

какой то аморфный объект...
нужна ясность...

Времени не хватает... :-(

13 (изменено: Xameleon, 2011-03-10 12:07:00)

Re: WSH: обмен данными и объектами между скриптами — 2

Товарищи, видимо пришло время раскрыть мои карты, раз Вы занялись таким подробным исследованием.

Этот объект я случайно обнаружил, "ковыряя" библиотеку shdocvw.dll через утилитку oleview (у кого нет - можете загрузить тут http://www.microsoft.com/downloads/en/d … laylang=en). Библиотеку shdocvw.dll, использует Internet Explorer для организации своей объектной модели. Собственно через неё мы и получаем возможности управления браузером. Ковырял я этот объект по причине поиска возможности из скрипта регистрировать окна в коллекции ShellWindows без создания посторонних процессов. Тест показал, что этот объект мне подходит.

Объект, который создаётся "волшебным способом" это один из Creatable (создаваемых) объектов этой библиотеки, именуемый ShellBrowserWindow. Почему его классида нет в реестре и как он при этом создаётся, если его нет - для меня тоже пока что остаётся загадкой. ) Информации на сайте мелкомягких о нём я не нашёл. Но можно поизучать его вручную.

Т.к он наследует интерфейс от WebBrowser2, то его методы можно посмотреть тут. (Либо через oleview. )

http://msdn.microsoft.com/en-us/library … s.85).aspx

[
  uuid(C08AFD90-F2A1-11D1-8455-00A0C91F3880),
  helpstring("Shell Browser Window."),
  hidden
]
coclass ShellBrowserWindow {
    [default] interface IWebBrowser2;
    interface IWebBrowserApp;
    [default, source] dispinterface DWebBrowserEvents2;
    [source] dispinterface DWebBrowserEvents;
};

Вот собственно всё, что пока известно мне. Но подозреваю, что могут всплыть и новые подробности и возможности.

P.S Копаю в сторону его hWnd. Уж очень интересно - где же он окошко создаёт.

Set ShellBrowserWindow = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
MsgBox ShellBrowserWindow.hwnd
ShellBrowserWindow.Visible = True

--
При попытке сделать его Visible - показывает окно обычного проводника. Занятно...

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

14

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

... Отдаю на тестирование...

Проверено на Win 2003 R2/2008/7 Pro. Везде работает, притом одинаково.

15

Re: WSH: обмен данными и объектами между скриптами — 2

Dmitrii пишет:
Xameleon пишет:

... Отдаю на тестирование...

Проверено на Win 2003 R2/2008/7 Pro. Везде работает, притом одинаково.

Благодарю. Очень признателен.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

16

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon, единственное, что я помню из прошлого обсуждения, что при перезапуске Проводника вот это будет пустым множеством:

Set ShellWindows = CreateObject("Shell.Application").Windows

Кажись, так, помнится…

Не пришло ещё время для Коллекции, а?!

17

Re: WSH: обмен данными и объектами между скриптами — 2

2 alexii:
1) Это да. Ну перезапуск - редкий случай. )
2) Для коллекции ? Думаю пока рано. Ещё JSman не сказал своё слово. ) Как он в JS перегонит, так наверное можно.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

18

Re: WSH: обмен данными и объектами между скриптами — 2

Кстати в js не работает. Но дождемся независимой экспертизы (-:

( 2 * b ) || ! ( 2 * b )

19 (изменено: JSmаn, 2011-03-11 00:14:50)

Re: WSH: обмен данными и объектами между скриптами — 2

Здравствуйте! Представляю черновую версию на JScript.

function GlobalObject(Name)
{    
    if(!Name)Name="GlobalObject";
    if (this.Window = this.FindWindow(Name))null;else
    {
        this.Window = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}");
        this.Window.StatusText = Name;
    }
}

GlobalObject.prototype = 
{
    FindWindow : function (Name)
    {
        var  ShellWindows=(new ActiveXObject("Shell.Application")).Windows();
        for (var i=ShellWindows.Count; --i>=0;)
        if (ShellWindows.Item(i).StatusText && ShellWindows.Item(i).StatusText.indexOf(Name)!=-1) 
        return ShellWindows.Item(i);
    },
    
    GetProperty: function (Name)
    {
        return this.Window.GetProperty(Name);
    },
    
    SetProperty: function (Name, Value)
    {
        this.Window.PutProperty(Name, Value);
    }

}

Примеры связи двух процессов

Файл номер 1.

var g = new GlobalObject();
g.SetProperty("Host", this);
while (1) WScript.Sleep(10);

Файл номер 2.

var g = new GlobalObject(), host;
if (host = g.GetProperty("Host")) 
{WScript.Echo("Связь установлена. Теперь закроем чужой процесс.");host.WScript.Quit();} else WScript.Echo("Связь не установлена")

Запускаем сначала первый файл, потом второй.

20

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata пишет:

Кстати в js не работает. Но дождемся независимой экспертизы (-:

У JSman-а не может не работать. )))

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

21

Re: WSH: обмен данными и объектами между скриптами — 2

Будете дополнять эту тему: WSH & HTA: обмен данными между скрипт-процессами или новую заведёте?

22

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:
Rumata пишет:

Кстати в js не работает. Но дождемся независимой экспертизы (-:

У JSman-а не может не работать. )))

Опечатался. [i] вместо .Item(i)

( 2 * b ) || ! ( 2 * b )

23

Re: WSH: обмен данными и объектами между скриптами — 2

Поправил немного свой код. Добавил открытие контейнера для хранения переменных под определённым именем. OpenContainer
2 alexii: Ммм. Наверное лучше допишем и в коллекцию перенесём. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

24

Re: WSH: обмен данными и объектами между скриптами — 2

Предлагаю отдельную тему завести коллеге Xameleon

25

Re: WSH: обмен данными и объектами между скриптами — 2

Можно, например, завести такую: «WSH: обмен данными и объектами между скриптами — 2». Немного будет отличаться заголовок, но это не страшно: кросс-посты я потом добавлю.

26

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

2 alexii: Ммм. Наверное лучше допишем и в коллекцию перенесём. )

Главное, не переборщите в итоге, дабы и простые смертные, такие, как я, могли бы в этом разобраться .

27

Re: WSH: обмен данными и объектами между скриптами — 2

Ну, что?) Теперь потоки на JS создавать можно:)

28

Re: WSH: обмен данными и объектами между скриптами — 2

2 alexii:
OFF: Как пожелаете. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

29

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon, это было только предложение. Решать в любом случае, как автору, Вам.

30 (изменено: Xameleon, 2011-03-11 02:13:26)

Re: WSH: обмен данными и объектами между скриптами — 2

2 alexii:

OFF: Вот я и решил, что согласен. ) Так искать будет проще потом.

Сейчас с JSman-ом обсудил варианты развития темы. Думаю скоро выложим ещё пару интересных примеров. Надеюсь, остальные участники тоже покреативят. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

31

Re: WSH: обмен данными и объектами между скриптами — 2

Я вот так переделал, но пример отличный.

Большое спасибо тебе Xameleon, давно что-то подобное ищу.

1.vbs

Class GlobalObject
    Private ShellWindow, ShellWindows

    Sub OpenContainer(name)
        Dim ShellWindows
        Set ShellWindows = CreateObject("Shell.Application").Windows
        For Each ShellWindow in ShellWindows
            if Instr(1,ShellWindow.StatusText,name) = 1 Then Exit Sub
        Next
        Set ShellWindow = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        ShellWindow.StatusText = name
    End Sub
    
    Property Let Value(name, newValue)    
        ShellWindow.PutProperty name, newValue
    End Property
    
    Public Default Property Get Value(name)
        On Error Resume Next
        if IsObject(ShellWindow.GetProperty(name)) Then
            Set Value = ShellWindow.GetProperty(name)
        Else
            Value = ShellWindow.GetProperty(name)
        End if
    End Property
End Class


Dim GlobalObj, fso
Set GlobalObj = New GlobalObject

set fso = CreateObject("Scripting.FileSystemObject")

GlobalObj.OpenContainer "storage"
GlobalObj("test") = InputBox("Введите значение для глобальной переменной ""test"".")
GlobalObj("fso") = fso

MsgBox "Значения установлены. Теперь, не закрывая это сообщение, запустите 2.vbs"

2.vbs

Class GlobalObject
    Private ShellWindow, ShellWindows

    Sub OpenContainer(name)
        Dim ShellWindows
        Set ShellWindows = CreateObject("Shell.Application").Windows
        For Each ShellWindow in ShellWindows
            if Instr(1,ShellWindow.StatusText,name) = 1 Then Exit Sub
        Next
        Set ShellWindow = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        ShellWindow.StatusText = name
    End Sub
    
    Property Let Value(name, newValue)    
        ShellWindow.PutProperty name, newValue
    End Property
    
    Public Default Property Get Value(name)
        On Error Resume Next
        if IsObject(ShellWindow.GetProperty(name)) Then
            Set Value = ShellWindow.GetProperty(name)
        Else
            Value = ShellWindow.GetProperty(name)
        End if
    End Property
End Class

Set GlobalObj = New GlobalObject

GlobalObj.OpenContainer "storage"
MsgBox "Значение переменной ""test"": " & GlobalObj("test") ,vbInformation
MsgBox "Тип переменной ""fso"": " & TypeName(GlobalObj("fso")),vbInformation

32 (изменено: Xameleon, 2011-03-11 11:55:03)

Re: WSH: обмен данными и объектами между скриптами — 2

2 atomix: Как ни странно, но я как раз с этого кода и начал. Только у меня было не Value, а Item Но меня смутил последующий метод присвоения объекта. Передавать его без Set меня напрягает.

GlobalObj("fso") = fso

А если уж делать через Set, то нужно отдельно описывать ещё и Property Set

Property Set Value(name, newValue)    
    ShellWindow.PutProperty name, newValue
End Property

В общем это меня и побудило на использование PutProperty и SetProperty. Вдобавок у самого объекта эти методы так реализованы. 

В кратце - чисто психологические заморочки. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

33

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon,

Win 2000 + SP4, IE6 - работает нормально.

Спасибо - вещь изящная и очень нужная.

34

Re: WSH: обмен данными и объектами между скриптами — 2

Для удобства объединил коды из поста №19 в один файл:

function GlobalObject(Name)
{    
    if(!Name)Name="GlobalObject";
    if (this.Window = this.FindWindow(Name))null;else
    {
        this.Window = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}");
        this.Window.StatusText = Name;
    }
}

GlobalObject.prototype = 
{
    FindWindow : function (Name)
    {
        var  ShellWindows=(new ActiveXObject("Shell.Application")).Windows();
        for (var i=ShellWindows.Count; --i>=0;)
        if (ShellWindows.Item(i).StatusText && ShellWindows.Item(i).StatusText.indexOf(Name)!=-1) 
        return ShellWindows.Item(i);
    },
    
    GetProperty: function (Name)
    {
/* 23 */        return this.Window.GetProperty(Name);
    },
    
    SetProperty: function (Name, Value)
    {
        this.Window.PutProperty(Name, Value);
    }

}

if ( WScript.Arguments.Named.Exists('1') ) {
    var g = new GlobalObject();
    g.SetProperty("Host", this);
    while (1) WScript.Sleep(10);
}

if ( WScript.Arguments.Named.Exists('2') ) {
    var g = new GlobalObject(), host;
    if (host = g.GetProperty("Host")) 
/* 42 */    {WScript.Echo("Связь установлена. Теперь закроем чужой процесс.");host.WScript.Quit();} else WScript.Echo("Связь не установлена")
}

.
Тест 1. Запускаем "инициализатор" затем "связного"

C:\PROGS\SCRIPTS\JavaScript\GlobalObject>cscript //nologo GlobalObject.js /1

C:\PROGS\SCRIPTS\JavaScript\GlobalObject>cscript //nologo GlobalObject.js /2
Связь установлена. Теперь закроем чужой процесс.

.
Тест 2. Через несколько секунд (до 1-2-3 минут) запускаем только "связного"

C:\PROGS\SCRIPTS\JavaScript\GlobalObject>cscript //nologo GlobalObject.js /2
Связь установлена. Теперь закроем чужой процесс.
C:\PROGS\SCRIPTS\JavaScript\GlobalObject\GlobalObject.js(42, 68) Microsoft JScript runtime error: The remote server machine does not exist or is unavailable

.
Тест 3. Через более продолжительное время запускаем опять только "связного"

C:\PROGS\SCRIPTS\JavaScript\GlobalObject>cscript //nologo GlobalObject.js /2
C:\PROGS\SCRIPTS\JavaScript\GlobalObject\GlobalObject.js(23, 9) Microsoft JScript runtime error: The remote server machine does not exist or is unavailable

Соответтствующие номера строк выставил в комментариях в начале строк.

( 2 * b ) || ! ( 2 * b )

35

Re: WSH: обмен данными и объектами между скриптами — 2

2 Rumata: Да. Есть некоторые "косяки". ) Связь с объектами пропадает не сразу. Как эти механизмы "лечить" надо подумать.

P.S Всё же HACK технология. Винда то и не думала, что её вывернут наизнанку и через её родные окошки будут данными кидаться.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

36

Re: WSH: обмен данными и объектами между скриптами — 2

JSman пишет:

Ну, что?) Теперь потоки на JS создавать можно:)

Можно поподробнее, как?

37

Re: WSH: обмен данными и объектами между скриптами — 2

2 mikser: Из того, что JSman объяснял мне при личной переписке - он имел в виду создание двух и более отдельных процессов. Т.е грубо говоря 2,3,4... процесса WScript.exe связанные через этот объект, выполняющие одну логическую задачу.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

38 (изменено: mikser, 2011-03-24 17:47:07)

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon, COM обёртки у WScript нету?
Что бы не создавать процесс WScript в лоб, а через new ActiveXObject("WScript.что то там") ?

39

Re: WSH: обмен данными и объектами между скриптами — 2

В общем, что касается потоков, то собираюсь на днях опубликовать код, который позволит делать вот такую штуку:

var worker = new Thread(Code, ObjectName, ObjectPointer, Language);
worker.attachEvent("oncomplete", callback);

Таким образом, трудоемкую часть кода можно вынести в отдельный процесс, снимая нагрузку с основного скрипта.

40

Re: WSH: обмен данными и объектами между скриптами — 2

mikser пишет:

Xameleon, COM обёртки у WScript нету?
Что бы не создавать процесс WScript в лоб, а через new ActiveXObject("WScript.что то там") ?

К сожалению нет. ) (ну или пока я её (COM обёртку) не нашёл)

На "вражеских" форумах и в блоге одно из разработчиков я видел подобный вопрос. Но везде ответ приблизительно такой - "ДА КАК ВАМ В ГОЛОВУ ТАКОЕ ПРИШЛО ?! ЗАЧЕМ ЭТО НУЖНО ?!" )) На что у меня возникает логичный ответ - "Ну раз спрашиваем ! Значит нужно !".

В общем подумаем, подумаем. Может и родим. ) На самом деле классид WScript-а известен.

[
  uuid(60254CA2-953B-11CF-8C96-00AA00B8708C),
  helpstring("Windows Script Host Object")
]
coclass IHost_Class {
    [default] interface IHost;
};

Но создать его как самостоятельный объект к сожалению нельзя. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

41 (изменено: kaster, 2011-03-25 13:22:00)

Re: WSH: обмен данными и объектами между скриптами — 2

Вариант на AutoIt
1.au3


$oContainer = OpenContainer("storage")
PutProperty($oContainer, "test", InputBox('', 'Введите значение для глобальной переменной "test".'))
$oFSO = ObjCreate("Scripting.FileSystemObject")
PutProperty($oContainer, "fso", $oFSO)

MsgBox(64, "", "Значения установлены. Теперь, не закрывая это сообщение, запустите 2.au3")

Func OpenContainer($sName)
    Local $oShell, $oShellWindow, $oShellWindows
    $oShell = ObjCreate("Shell.Application")
    $oShellWindows = $oShell.Windows
   
    For $oShellWindow In $oShellWindows
        If StringInstr($oShellWindow.StatusText, $sName) Then
            Return $oShellWindow
        EndIf
    Next
   
    $oContainer = ObjGet("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
    $oContainer.StatusText = $sName
   
    Return $oContainer
EndFunc

Func PutProperty($oContainer, $sName, $vValue)
    $oContainer.PutProperty($sName, $vValue)
EndFunc

Func GetProperty($oContainer, $sName)
    Return $oContainer.GetProperty($sName)
EndFunc

2.au3


$oContainer = OpenContainer("storage")
PutProperty($oContainer, "test", InputBox('', 'Введите значение для глобальной переменной "test".'))
$oFSO = ObjCreate("Scripting.FileSystemObject")
PutProperty($oContainer, "fso", $oFSO)

MsgBox(64, "", "Значения установлены. Теперь, не закрывая это сообщение, запустите 2.au3")

Func OpenContainer($sName)
    Local $oShell, $oShellWindow, $oShellWindows
    $oShell = ObjCreate("Shell.Application")
    $oShellWindows = $oShell.Windows
   
    For $oShellWindow In $oShellWindows
        If StringInstr($oShellWindow.StatusText, $sName) Then
            Return $oShellWindow
        EndIf
    Next
   
    $oContainer = ObjGet("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
    $oContainer.StatusText = $sName
   
    Return $oContainer
EndFunc

Func PutProperty($oContainer, $sName, $vValue)
    $oContainer.PutProperty($sName, $vValue)
EndFunc

Func GetProperty($oContainer, $sName)
    Return $oContainer.GetProperty($sName)
EndFunc

Автор реализации: Creator

autoit@conference.jabber.ru - Конференция скриптового языка AutoIt на jabber.ru

42 (изменено: mikser, 2011-03-25 23:02:37)

Re: WSH: обмен данными и объектами между скриптами — 2

OFF: Наткнулся на интересный  COM объектик, Который может добавить многопоточность в скрипты.
COMScriptThread

Name Description
Start Starts the thread with the given script
Execute If the thread is started and in stand-by executes the given routine from the loaded script.
Stop Stops the thread.
Wait Waits for the thread to complete the current operation.
Value Default property: Holds a VarDictionary based collection (dictionary) that is accessible for the both - the application creating the thread and the script in the thread.
Busy Boolean: indicates if the thread is busy.
AddCreator Boolean: If set the running script in the thread will have a Pack1Creator object accessible through the Creator namespace.
LastError String: Contains the last error
MultiThreaded Boolean: If set (default) the thread will be initialized as multithreaded COM apartment.
Priority Integer: The thread priority
Result Variant: The result of the last routine execution (meaningful if the routine is a function)
Success Boolean: Indicates if the last operation was successful (routine execution, thread start)
Timeout Positive integer: Timeout for the internal wait operations.
Active Indicates if the thread is active (Busy or stand by)

43

Re: WSH: обмен данными и объектами между скриптами — 2

Фи. Сторонняя разработка. Не системный COM. Не айс. ) Если делать стороннюю - то я уж лучше сам соберу. По крайней мере буду точно знать где накосячил. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

44

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon
Просим! Многопоточности скриптовым языкам очень не хватает (имею в виду AutoIt. Но думаю, AHK тоже, а вот на Python есть свою либа, как мне известно).

autoit@conference.jabber.ru - Конференция скриптового языка AutoIt на jabber.ru

45

Re: WSH: обмен данными и объектами между скриптами — 2

Да собственно всё уже решено до нас - WshController. Не очень удобно, ибо требует настройки на локальном компе. Но куда уж многопоточнее ? ) Либо ScriptControl как вариант.

Можно и своё нагородить. Но хоть убейте - не вижу смысла.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

46

Re: WSH: обмен данными и объектами между скриптами — 2

Угу. Если задуматься — зачем? — то реальных приложений, не просто требующих многопоточности, а и умеющих её использовать — раз-два и обчёлся.

47

Re: WSH: обмен данными и объектами между скриптами — 2

alexii, из практики. После создания GUI, если скрипт занят чем-то (к примеру, обработкой большого файла), то сам GUI уже ни на что не реагирует. Если повесить прорисовку графики на один поток, все остальное на другой - проблема решается. Более того, можно начать обрабатывать другой файл, к примеру. Я уже не говорю, про индикацию прогресса. Наверняка, у многих (по крайней мере, на соответствующем форуме) возникали индивидуальные требования так или иначе требующие многопоточности. Я лично все свои подобные проблемы решил использовав Python, т.к. там есть модуль threading.

autoit@conference.jabber.ru - Конференция скриптового языка AutoIt на jabber.ru

48

Re: WSH: обмен данными и объектами между скриптами — 2

kaster пишет:

alexii, из практики. После создания GUI, если скрипт занят чем-то (к примеру, обработкой большого файла), то сам GUI уже ни на что не реагирует. Если повесить прорисовку графики на один поток, все остальное на другой - проблема решается. Более того, можно начать обрабатывать другой файл, к примеру. Я уже не говорю, про индикацию прогресса.

Отчасти согласен. Но я имел в виду несколько иное — саму обработку (GUI в AutoIt — частный случай, и, в принципе, не слишком критичный — обработку можно вынести даже в отдельное приложение).

49

Re: WSH: обмен данными и объектами между скриптами — 2

alexii, да, какие только костыли я не пробовал Если повесить обработку графики на отдельный скрипт, код нагромождается необходимостью (грамотной) организации обменом данных между двумя скриптами. Я, к примеру, про метод обсуждаемый в данной теме не знал. Посему это дело забросил. Но в любом случае, если будет возможность сделать такое относительно простыми способами, как мультипоточность, никто против не будет

autoit@conference.jabber.ru - Конференция скриптового языка AutoIt на jabber.ru

50 (изменено: mikser, 2011-03-29 04:23:42)

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

Но хоть убейте - не вижу смысла.

Жаль а мне бы она щас не помешала. Я сегодня окончательно осознал как применять LibCurl в среде JScript через DynamicWrapperX
проблема осталась лишь в том, что все запросы в курле синхроные а для асинхроных запросов авторы курла советуют юзать потоки.

Фи. Сторонняя разработка. Не системный COM. Не айс. )

Зато бесплатная. А системные комы тоже не всегда айс,  и их исходников у вас нету.
Скорей всего в системных комах косяков не меньше чем в сторонних разработках.

Xameleon пишет:

Либо ScriptControl как вариант.

Не знал, что он это позволяет, а можно пример многопоточности через ScriptControl?

51

Re: WSH: обмен данными и объектами между скриптами — 2

kaster, я обычно обхожусь консольным интерфейсом, в цикличный код достаточно просто добавить вывод на консоль, потому я особо многопоточностью и не интересовался.

Реально, где многопоточность мне требовалась — в одновременном опросе N-ного числа машин посредством WMI (ибо практикуемый многими последовательный опрос растягивается на очень длительное время, особливо при наличии выключенных машин). Данный вопрос решился этой темой: VBScript: асинхронная обработка множественных запросов WMI.

52

Re: WSH: обмен данными и объектами между скриптами — 2

На мой взгляд для "псевдомногопоточности" можно использовать setInterval и setTimeout.

В этой теме
я как раз и привёл такой пример.

------ добавил позже ------

Хотели многопоточности ? Принимайте. )

Создаём 3 псевдопотока. ))


Dim log, Thread1, Thread2, Thread3, state

Set Thread1 = New clsThread
Set Thread2 = New clsThread
Set Thread3 = New clsThread

Thread1.Start getRef("Proc1")
Thread2.Start getRef("Proc2")
Thread3.Start getRef("Proc3")

Sub Proc1
    For i=1 to 9000000
    Next
    log = log & Time & ": Proc1 complete" & vbCrlf
    state = state + 1
End Sub

Sub Proc2
    For i=1 to 10000
    Next
    log = log & Time & ": Proc2 complete" & vbCrlf
    state = state + 1
End Sub

Sub Proc3
    For i=1 to 100
    Next
    log = log & Time & ": Proc3 complete" & vbCrlf
    state = state + 1
End Sub

Do
    WScript.Sleep 100
Loop Until State => 3

MsgBox log

Class clsThread
    Private document
    Private Sub Class_Initialize()
        set document = CreateObject("htmlfile")
    End Sub
    Sub Start(proc)
        document.parentWindow.setTimeout proc,0
    End Sub
End Class
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

53

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

Да собственно всё уже решено до нас - WshController. Не очень удобно, ибо требует настройки на локальном компе. Но куда уж многопоточнее ? ) Либо ScriptControl как вариант.

Можно и своё нагородить. Но хоть убейте - не вижу смысла.

alexii пишет:

Угу. Если задуматься — зачем? — то реальных приложений, не просто требующих многопоточности, а и умеющих её использовать — раз-два и обчёлся.

Вот реальный пример надобности многопоточности

Времени не хватает... :-(

54 (изменено: Евген, 2011-03-29 19:32:36)

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

Создаём 3 псевдопотока. ))

Как этот пример кода переделать под произвольное количество потоков (от 1 до 30-ти) ?
Под пример использования в одном посте выше...

Времени не хватает... :-(

55

Re: WSH: обмен данными и объектами между скриптами — 2

Евген, избегайте излишнего цитирования. Я поправил Ваш пост.

56

Re: WSH: обмен данными и объектами между скриптами — 2

2 alexii Виноват, исправлюсь...

Времени не хватает... :-(

57 (изменено: mikser, 2011-03-29 20:29:18)

Re: WSH: обмен данными и объектами между скриптами — 2

На сколько я понял ключевой момент в коде хамелеона это CreateObject("htmlfile")
то есть создаем много хтмл документов и внутри них все исполняется в отдельных "потоках".

Тока тут одна проблема - если внутри созданого html документа создать какой-нить потенциально опасный ActiveX объект типа FileSystemObject то
виндовс вас спросит а вы доверяете этому приложению? и так для каждого потока. Как это отключить не знаю

58

Re: WSH: обмен данными и объектами между скриптами — 2

2 Евген: А самому попытаться ? ) Я вроде и так максимально простой пример сгенерил.
2 mikser: А кто сказал, что мы будем создавать потенциально опасные объекты внутри htmlfile ? От него нам нужен только setTimeout. А потенциально опасные объекты у нас все в WSH. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

59

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon, если добавить вывод и, для наглядности, немного поменять местами:

Dim log, Thread1, Thread2, Thread3, state
 
Set Thread1 = New clsThread
Set Thread2 = New clsThread
Set Thread3 = New clsThread
 
Thread1.Start getRef("Proc1")
Thread2.Start getRef("Proc2")
Thread3.Start getRef("Proc3")
 
Sub Proc1
    For i=1 to 90000
        WScript.StdOut.Write "1"
    Next
    log = log & Time & ": Proc1 complete" & vbCrlf
    state = state + 1
End Sub
 
Sub Proc2
    For i=1 to 100
        WScript.StdOut.Write "2"
    Next
    log = log & Time & ": Proc2 complete" & vbCrlf
    state = state + 1
End Sub
 
Sub Proc3
    For i=1 to 10000
        WScript.StdOut.Write "3"
    Next
    log = log & Time & ": Proc3 complete" & vbCrlf
    state = state + 1
End Sub
 
Do
    WScript.Sleep 100
Loop Until State => 3
 
MsgBox log
 
Class clsThread
    Private document
    Private Sub Class_Initialize()
        set document = CreateObject("htmlfile")
    End Sub
    Sub Start(proc)
        document.parentWindow.setTimeout proc,0
    End Sub
End Class

то становится видно, что многопоточности, увы, нет. Процедуры исполняются строго последовательно, в порядке, обратном созданию.

60

Re: WSH: обмен данными и объектами между скриптами — 2

2 alexii: Мда. Видимо придётся покорпеть над GlobalObject ) Эх.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

61

Re: WSH: обмен данными и объектами между скриптами — 2

Потому что нельзя передавать ссылки на функции, так как они будут исполняться в контексте их потока

62

Re: WSH: обмен данными и объектами между скриптами — 2

2 JSman: Так точно. ) Что MsgBox, что StdOut.WriteLine и циклы. Всё это держит основной поток. Как раз думаю - стоит ли на GlobalObject вешать отдельные процессы или нет. Пока в сомнениях.

Либо надо выносить необходимый код во внешние элементы. К примеру в WSC и исполнять его в контексте этих объектов.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

63

Re: WSH: обмен данными и объектами между скриптами — 2

Есть возможность вешать все на ScriptControl, но при этом о WScript можно забыть. С другой стороны использовать GlobalObject вполне безопасно для основного скрипта.

64

Re: WSH: обмен данными и объектами между скриптами — 2

Есть идея использовать mshta. В принципе код можно генерировать на лету, получать асинхронные события, не использовать WScript.Sleep.

65

Re: WSH: обмен данными и объектами между скриптами — 2

2 JSman: От слов к действиям. Есть что посмотреть ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

66

Re: WSH: обмен данными и объектами между скриптами — 2

http://funportal.info/smiles/smile284.gif

autoit@conference.jabber.ru - Конференция скриптового языка AutoIt на jabber.ru

67 (изменено: mikser, 2011-03-30 04:34:40)

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

Либо ScriptControl как вариант.

JSman пишет:

Есть возможность вешать все на ScriptControl,

Да расскажите уже наконец как вы запустите ScriptControl'овский код в отдельном потоке?
Код в скрипт контроле синхронно с основным кодом выполняется.

68 (изменено: Евген, 2011-03-30 15:08:20)

Re: WSH: обмен данными и объектами между скриптами — 2

Коллеги, вот мой вариант создания многопоточности WshController (не до конца рабочий - не пойму почему), аргумент потоку приходит, процесс создаётся, признак нормального завершения удалённого процесса по статусу есть.
Почему не отрабатывает на удалённом хосте - ХЗ
Кто сможет помочь ?

SN="SomeScript.vbs"
Set fso = CreateObject("Scripting.FileSystemObject")
ParentFolderName = fso.GetParentFolderName(Wscript.ScriptFullName) 
DestFilePath = fso.BuildPath(ParentFolderName,SN) 
LF="result.log"


If Wscript.Arguments.Count=0 Then  ' признак основного потока

arrComputers = Array("strhost02","strhost03","strhost04","strhost06","strhost07","strhost08","strhost10","strhost13","strhost14","strhost15","strhost16","strhost17","strhost18","strhost20","strhost21","strhost22","strhost23","strhost24","strhost25","strhost26","strhost27","strhost29")


Set objService     = GetObject("winmgmts:\\.\Root\CIMV2")
Set objSinkProcess = WScript.CreateObject("WbemScripting.SWbemSink", "SinkProcess_")
objService.ExecNotificationQueryAsync objSinkProcess, "SELECT * FROM __InstanceDeletionEvent WITHIN 0.2 WHERE TargetInstance ISA 'Win32_Process'"
Set objSinkPing    = WScript.CreateObject("WbemScripting.SWbemSink", "SinkPing_")
Set objProcess     = objService.Get("Win32_Process")
Set objDictionary  = CreateObject("Scripting.Dictionary")



ret=LogEvent(String(28,"-") & " " & date & "  " & time & String(28,"-"))

bdoneping    = False
bdoneprocess = False
strCount=0
intThread=0

For Each strComputer In arrComputers
  Set objContext = CreateObject("WbemScripting.SWbemNamedValueSet")
  objContext.Add "hostname", strComputer
  objService.ExecQueryAsync objSinkPing, "select * from Win32_PingStatus where address ='" & strComputer & "'", , , , objContext
Next

While Not bdoneping

If strCount=ubound(arrComputers)+1 Then
bdoneping=True
End If
WScript.Sleep 100

Wend

objSinkPing.Cancel


While Not bdoneprocess

If intThread=0 and bdoneping=True Then
bdoneprocess=True
End If
WScript.Sleep 100

Wend

objSinkProcess.Cancel

MsgBox "Готово !!!"


Else           ' признак потока с аргументом
strComputer=WScript.Arguments(0)
ret=LogEvent(strComputer & " - argument OK")
Set oController = CreateObject("WSHController")

On Error Resume Next
Set oProcess = oController.CreateScript(SN,strComputer)   ' вот здесь надо полный путь к файлу скрипта писать
oProcess.Execute
If Err.Number<>0 Then  '2
ret=LogEvent(strComputer & " - Connection Error !!!")
Err.Clear
On Error Goto 0
Else                   '2                  ' если нет ошибок при удалённом запуске
Do While oProcess.Status <> 2              ' ждём окончания удалённой работы скрипта
    WScript.Sleep 100
Loop
Set oController = Nothing
ret=LogEvent(strComputer & " - Ok !!!")
End If

End If        ' конец условия по признакам потоков


Function LogEvent(strInput)
Set fso = CreateObject("Scripting.FileSystemObject")
ParentFolderName = fso.GetParentFolderName(Wscript.ScriptFullName) 
DestFilePath = fso.BuildPath(ParentFolderName,LF) 
Set objFile = fso.OpenTextFile(DestFilePath, 8, True)
objFile.WriteLine strInput
objFile.Close
End Function



Sub SinkPing_OnObjectReady(objWbemObject, objWbemAsyncContext)
strCount=strCount+1
Set strComputer = objWbemAsyncContext.Item("hostname")
res=""
  Select Case objWbemObject.StatusCode
    Case 0        ' хост пингуется
	objProcess.Create "wscript.exe " & Wscript.ScriptFullName & " " & strComputer, null, null, intProcessID
	objDictionary.Add intProcessID, intProcessID
	intThread=intThread+1
	ret=LogEvent("PID: " & intProcessID)
    Case Else     ' хост не пингуется
	ret=LogEvent(strComputer & " - not respond to ping")
  End Select
End Sub




Sub SinkProcess_OnObjectReady(objLatestEvent, objAsyncContext)  
	ret=LogEvent("Terminate PID: " & objLatestEvent.TargetInstance.ProcessID)
   If objDictionary.Exists(objLatestEvent.TargetInstance.ProcessID) Then
	objDictionary.Remove(objLatestEvent.TargetInstance.ProcessID)
	intThread=intThread-1
	ret=LogEvent("Thread: " & intThread & "        " & objDictionary.Count)
   End If

End Sub
Времени не хватает... :-(

69 (изменено: Евген, 2011-03-30 08:42:04)

Re: WSH: обмен данными и объектами между скриптами — 2

При запуске скрипта с параметром на удалённом хосте нормально отрабатывает посылаемый на выполнение скрипт, а когда сам себя плодит - то не отрабатывает...


Хоть опишу принцип работы:
        Работа без аргумента - основной (управляющий) скрипт
1) асинхронно пингуем удалённые хосты
2) по каждому откликнувшемуся на пинг хосту создаём поток (запускаем самого себя с аргументом имя хоста) запоминаем его ProcessID в словарь
3) асинхронно мониторим события по завершению процессов
4) если попадаются наши ID процессов - то учитываем их
5) как все созданные процессы завершаться - сигнализируем о завершении
6) всё хозяйство логируем в файле "result.log"
        Работа с аргументом (созданный поток) - результат работы управляющего потока (запуск самого себя с аргументом)
1) получаем аргумент
2) поднимаем объект wshcontroller
3) запускаем на удалённом хосте указанный скрипт
4) дожидаемся признака нормального завершения удалённого скрипта
5) логируем удачное/неудачное завершение

Времени не хватает... :-(

70

Re: WSH: обмен данными и объектами между скриптами — 2

Коллеги, дико извиняюсь...
в WshControllere надо было указать полный путь к скрипту посылаемому на удалённое выполнение.

А так - вариант польностью рабочий !!!  :-)

Кого заинтересовало - подправьте и пользуйтесь...

Времени не хватает... :-(

71 (изменено: Евген, 2011-04-01 19:15:20)

Re: WSH: обмен данными и объектами между скриптами — 2

Свой скрипт немного модифицировал, добавил ограничение потоков очередью, что придало стабильность работе скрипта и поместил в коллекцию.
Старый вариант иногда вешал компьютер, видимо из-за того, что у Windows XP есть ограничение на 10 одновременных соединений по TCP/IP протоколу , и из-за этого EventLog украшался "кирпичами" по событиям DCOM, сейчас очередь ограничил 8 потоками - и скрипт заработал стабильно, не "вешая" систему.

Времени не хватает... :-(

72

Re: WSH: обмен данными и объектами между скриптами — 2

Евген, желательно не забывать про вложенные отступы — это повышает читабельность кода.

73 (изменено: Rumata, 2011-04-27 12:07:40)

Re: WSH: обмен данными и объектами между скриптами — 2

Первоначально объект назывался ConnectObject. В связи с тем, что существует одноименный метод WScript.ConnectObject, и чтобы избежать возможной путаницы, объект был переименован в GlobalContainer. Соответственно, все упоминания ConnectObject были изменены на GlobalContainer как в тексте, так и коде. Это изменение было сделано после дальнейшего обсуждения в этой же теме.

Решил вернуться к основам этой темы. За основу взял код, представленный JSman, но внес некоторые изменения и дополнения. Мне показалось, что GlobalObject это спорное название для объекта, так как во всех диалектах Javascript существует глобальный объект. Поэтому объект назван GlobalContainer, чтобы не было путаницы и точнее отражалось назначение объекта. Но это косметические изменения. После различных тестов было добавлено несколько строк для перехвата возможных исключений. Например, если первичный скрипт был преждевременно завершен, то в созданном объекте остаются "мертвые" ссылки на уже несуществующие объекты, таким образом присваивание значения, возвращаемого методом IWebBrowser2::GetProperty приводит к исключению. Добавлен метод GlobalContainer::close(), который отчасти помогает корректно закрыть объект IWebBrowser2.

GlobalContainer.js



function GlobalContainer(signature)
{
	signature = signature || GlobalContainer.signature;

	this.appWindow = GlobalContainer.getInstance(signature);

	if ( ! this.appWindow ) {
		this.appWindow = GetObject('new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}');
		this.appWindow.StatusText = signature;
	}
};

GlobalContainer.signature = 'GlobalContainer';

GlobalContainer.getInstance = function(signature)
{
	signature = signature || GlobalContainer.signature;
	var appList = (new ActiveXObject('Shell.Application')).Windows();
	var i = appList.Count;
	while ( i-- ) {
		var e;
		try {
			var app = appList.Item(i);
			if ( app.StatusText && app.StatusText.indexOf(signature) == 0 ) {
				return app;
			}
		} catch (e) {
		}
	}
};

GlobalContainer.prototype.getProperty = function(name)
{
//	return this.appWindow.GetProperty(name);
	var e;
	try {
		return this.appWindow.GetProperty(name);
	} catch (e) {
	}
};

GlobalContainer.prototype.setProperty = function(name, value)
{
//	return this.appWindow.PutProperty(name, value);
	var e;
	try {
		return this.appWindow.PutProperty(name, value);
	} catch (e) {
	}
};

GlobalContainer.prototype.close = function()
{
//	return this.appWindow.Quit();
	var e;
	try {
		return this.appWindow.Quit();
	} catch (e) {
	}
};

Тестовый файл
test.js



if ( WScript.Arguments.Named.Exists('init') ) {

	var flag = false;

	var co = new GlobalContainer();
	co.setProperty('that', this);

	while ( ! flag ) {
		WScript.Sleep(10);
	}

	WScript.Echo("Эта строка выполняется не всегда!!!");
	co.close();

}

if ( WScript.Arguments.Named.Exists('soft') ) {

	var co = new GlobalContainer();
	var that = co.getProperty('that');

	if ( ! that ) {
		WScript.Echo("Связь не обнаружена.");
	} else {
		WScript.Echo("Обнаружена связь с внешним процессом.");
		var e;
		try {
			WScript.Echo("Попытаемся мягко завершить внешний процесс.");
			that.flag = true;
		} catch (e) {
			WScript.Echo("Попытка мягко завершить неудачна. Возможно процесс уже удален.");
		}
	}

	WScript.Echo("Закроем связного.");
	co.close();

}

if ( WScript.Arguments.Named.Exists('hard') ) {

	var co = new GlobalContainer();
	var that = co.getProperty('that');

	if ( ! that ) {
		WScript.Echo("Связь не обнаружена.");
	} else {
		WScript.Echo("Обнаружена связь с внешним процессом.");
		var e;
		try {
			WScript.Echo("Попытаемся жестко завершить внешний процесс.");
			that.WScript.Quit();
		} catch (e) {
			WScript.Echo("Попытка жестко завершить неудачна. Возможно процесс уже удален.");
		}
	}

	WScript.Echo("Закроем связного.");
	co.close();

}

Других примеров у меня нет, поэтому довольствовался существующими примерами.

Тестирование
test.wsf


<?xml version="1.0" encoding="utf-8" ?>

<package>
<job id="wscmd">
<?job error="true" debug="false" ?>
<script language="javascript" src="./GlobalContainer.js"></script>
<script language="javascript" src="./test.js"></script>
</job>
</package>

Мягкое закрытие процесса
1. в отдельном окне выполнить

cscript //nologo test.wsf /init

2. в другом окне выполнить

cscript //nologo test.wsf /soft

Жесткое закрытие процесса
3. в отдельном окне выполнить

cscript //nologo test.wsf /init

4. в другом окне выполнить

cscript //nologo test.wsf /hard

Повторить пункты 1-4, но после пунктов 1 и 3 эмулировать аварийное завершение процесса по CTRL+C,

( 2 * b ) || ! ( 2 * b )

74

Re: WSH: обмен данными и объектами между скриптами — 2

OFF:

Rumata пишет:

Поэтому объект назван ConnectObject, чтобы не было путаницы…

Есть такой метод в WSH — тоже получается как бы не зер гут.

75 (изменено: Rumata, 2011-04-26 21:44:50)

Re: WSH: обмен данными и объектами между скриптами — 2

Есть такой метод в WSH

Не знал о его существовании. Пересечение имен объекта и метода вроде бы не критично. Может быть GlobalConnect? Хотя... Польза от этого объекта невелика.

( 2 * b ) || ! ( 2 * b )

76

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata пишет:

Пересечение имен объекта и метода вроде бы не критично.

Угу.

Речь именно про возможную путаницу.

77

Re: WSH: обмен данными и объектами между скриптами — 2

Хорошо. Думаю, что никто не будет против, если я внесу соответствующие правки в свой пост #73:

s/ConnectObject/GlobalConnect/g
( 2 * b ) || ! ( 2 * b )

78

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata пишет:

Мне показалось, что GlobalObject это спорное название для объекта, так как во всех диалектах Javascript существует глобальный объект.

Отнюдь. GlobalObject — это теоретический объект, начало иерархии объектов JavaScript от Microsoft. В общем, это this в глобальном контексте.

79

Re: WSH: обмен данными и объектами между скриптами — 2

GlobalObject — это теоритический объект

Что значит "теоретический"? Есть спецификация языка ECMAScript. Javascript и JScript - соответствующие реализации. Глобальный объект реален, доступ к нему осуществляется посредством this.

Цитата из документа ECMA-262, стр. 2 (Также глобальный объект подробно описан в отдельном разделе спецификации)

ECMAScript defines a collection of built-in objects that round out the definition of ECMAScript entities. These built-in objects include the global object, ... (дальше идет перечисление всех встроенных объектов)

( 2 * b ) || ! ( 2 * b )

80

Re: WSH: обмен данными и объектами между скриптами — 2

А я в GlobalContainer переименовал. На мой взгляд как то логичнее звучит. В первом посте уже давно поправил. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

81

Re: WSH: обмен данными и объектами между скриптами — 2

Хотя GlobalContainer тоже спорно (объект ничего не хранит, он только создает невидимое окно для связи). Наверно, логичнее было назвать GlobalConnector. Но я последовал Вашему примеру - идея, название. И добавил несколько вступительных слов.

( 2 * b ) || ! ( 2 * b )

82

Re: WSH: обмен данными и объектами между скриптами — 2

Как не хранит ? Мы же через методы PutProperty и GetProperty передаём ему данные ? Передаём. Да, в случае объектов хранится только ссылка, но в случае строк и числовых данных, реально хранятся сами данные.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

83

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata пишет:

Глобальный объект реален, доступ к нему осуществляется посредством this.

Опять же повторяю, что это теоретическое понятие. С точки зрения практики — это только this в глобальном контексте. И все, и никакого GlobalObject. Хотите оспорить: приведите код без this (и без window ).

84

Re: WSH: обмен данными и объектами между скриптами — 2

Поднимаю старую тему. Как разминка для ума.

Просматривая список последних изменений на форуме, увидел две интересные темы Перенумерация файлов и папок и Переименование файлов с использование регулярных выражений. Сразу вспомнилось данное обсуждение. Появилась идея -- как можно было бы объединить все изложенные идеи воедино. Например, есть некий скрипт, который ищет файлы по маске и (по умолчанию) выводит полученный список. При задании определенным параметром второго скрипта выполняются инструкции второго скрипта, например:


:: простой вывод списка файлов
cscript FindFiles.vbs "*.vbs" "*.js"

:: перенумерация файлов и папок
cscript FindFiles.vbs "*.vbs" "*.js" /exec:vrenum.vbs <Опции для vrenum>

:: переименование файлов
cscript FindFiles.vbs "*.vbs" "*.js" /exec:vrenn.vbs <Опции для vrenn>
( 2 * b ) || ! ( 2 * b )

85

Re: WSH: обмен данными и объектами между скриптами — 2

Rumata, задача тривиальна. Может стоит направить усилия на создание потоков?

86

Re: WSH: обмен данными и объектами между скриптами — 2

JSman, согласен, что задача тривиальна. К сожалению, не вижу путей оптимальной реализации потоков средствами WSH. Предложенная идея - всего лишь иллюстрация применения данной идеи.

( 2 * b ) || ! ( 2 * b )

87

Re: WSH: обмен данными и объектами между скриптами — 2

Всем доброго времени суток. Внёс изменения в код и исправил ошибки (см. первый пост). Экземпляры объекта ShellBrowserWindow оставались в памяти после выгрузки класса.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

88

Re: WSH: обмен данными и объектами между скриптами — 2

Доброго времени суток. Опробовал скрипты из 1 поста, все замечательно. Запустил чуть позднее еще раз - ошибка! Как выяснилось, "Ошибка: Неопознанная ошибка Код: 80004005 Источник: (null)" возникает в 1 скрипте в строке 16 при вызове метода wnd.StatusText. Ошибка начала появляться после запуска моего скрипта, в котором создается объект

set ie = wscript.createobject("internetexplorer.application")

Создание в моем скрипте окна ie для вывода данных сопровождается появлением (по крайней мере на моей машине) в диспетчере 2 процессов iexplore.exe, например:
CommandLine: "C:\Program Files (x86)\Internet Explorer\iexplore.exe" SCODEF:8432 CREDAT:145409
CommandLine: "C:\Program Files (x86)\Internet Explorer\iexplore.exe" -Embedding
После завершения этих процессов оба скрипта из 1 поста вновь начинают работать без ошибок.
Windows 7 Домашняя Базовая, Service Pack 1, x64;
IE 9.0.8112.16421, Выпуски обновления 9.0.12 (KB2761465).
Результат не меняется в зависимости от запуска скриптов в \SysWOW64\WScript.exe, либо \System32\WScript.exe.

Можно ли как-то обойти данную ошибку?

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

89

Re: WSH: обмен данными и объектами между скриптами — 2

omegastripes
Попробуйте выгружать объект и процесс в Вашем скрипте:
ie.ExecWB 45, 2 : ie.Quit
Я на Win7 этим всегда пользуюсь, когда отправляю что-то в буфер.

90

Re: WSH: обмен данными и объектами между скриптами — 2

Всем спасибо за ответы.

Flasher, я не уточнил в предыдущем посте, что цели выгрузить ie не преследуется, напротив, действующий ie не должен вызывать ошибку в GlobalContainer.

Xameleon, для конкретики приведу такой скрипт:

0.vbs

set logger = new logwindow
do
    logger.write now
    wscript.sleep 1000
loop

class logwindow
    
    private ie
    
    private sub class_initialize()
        set ie = wscript.createobject("internetexplorer.application", "ie_")
        with ie
            .menubar = false
            .toolbar = false
            .resizable = true
            .statusbar = false
            .addressbar = false
            .visible = true
            .navigate "about:blank"
        end with
    end sub
    
    public sub write(text)
        ie.document.write(text & "<br>")
    end sub
    
    private sub class_terminate()
        on error resume next
        ie.quit
    end sub
    
end class

sub ie_onquit
    wscript.quit
end sub

После запуска появится окно ie, в который скрипт будет что-то писать. Если после этого запустить 1.vbs из первого поста - вылетает ошибка, которую я описывал выше.

Все заработало после замены метода Open класса GlobalContainer в скриптах из первого поста на одноименный из GlobalContainer.wsc Вашего примера! По всей видимости ошибку выдавал .StatusText окна ie. Предлагаю обновить GlobalContainer в первом посте.

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

91

Re: WSH: обмен данными и объектами между скриптами — 2

2 omegastripes: Да. Видимо проблема была именно в StatusText. Ок. Попробую заменить в первом посте. ) Забавно. Я думал, что тема не просуществует больше недели.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

92

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

Надеюсь, остальные участники тоже покреативят. )

Доброго всем времени суток. Ранее уже поднимался вопрос о многопоточности JS/VBS, готовых решений я не нашел, поэтому предлагаю костыль, реализующий механизм многопоточности (а точнее «многопроцессности») для WSH VBScript. Не рекомендуется лицам с аллергией на индокод. Подробнее:

+ открыть спойлер

Особенности:
• Запущенный скрипт выполняет служебную функцию. Основной код выполняется в последующих процессах.
• В «полной версии» основной код размещается только в классах, экземпляр любого из которых можно создать в отдельном процессе. В каждом новом процессе скрипт создает экземпляр служебного класса, который создает экземпляр указанного целевого класса, вызывает целевой метод, контролирует его ход, создает в глобальном контексте скриптов переменные, ссылающиеся на созданные экземпляры классов. В предшествующий скрипт возвращается объект инициализированного целевого класса, и «обрабатываются» события инициализации и завершения целевого класса запущенного скрипта.
• В «легкой версии» логика аналогична, только основной код размещается внутри sub’ов, предшествующему скрипту возвращается не объект, а индекс запущенного, и нет обработки событий.
• Для создания нового процесса скрипт рекурсивно запускает самого себя, передав данные о вызываемом методе и идентифицирующую информацию в именованном аргументе.
• Единого пространства исполнения нет, каждый скрипт хранит свои данные и объекты в своем контексте. Для обмена данными объект Me первого скрипта передается в последующие с применением GlobalContainer, описанным в этой теме. Каждый скрипт после завершения целевого метода ожидает разрешения на завершение, такая задержка позволяет забрать из него полученную информацию.
• Функционирует одинаково в WSH WScript и CScript, и в виде скомпилированного в ScriptCryptor exe-файла (правда, в exe не работают методы class_terminate).

Минусы:
• Сложность в отладке из-за использования во многих методах on error resume next и execute. Все ж таки это костыль.
• Громоздкость.
• Порядок завершения скриптов полностью в ответственности разработчика. Естественно, при обращении к объектам завершенного скрипта возникнет ошибка.

Актуально:
• Не реализованы мьютексы и механизмы залочивания метода от использования более чем одним процессом.
• Возможны сбои при одновременном доступе к переменным скрипта из контекстов других.
• Окно проводника остается в памяти при закрытии окна консоли CScript.exe.

Первая мысль о потенциальных удобствах многопоточности пришла однажды во время решения на добровольных началах относительно несложной задачи по обработке и визуализации информации. И, поскольку установка IDE навроде Visual Studio и наш Helpdesk - понятия несовместимые, из «легальных» оставались только VBA и WSH. В то время был выбран последний. А действующие административные ограничения и желание получить дружественные методы продиктовали требования к данной реализации многопроцессности:
• Код расположен в одном файле, как обычный сценарий.
• Использует минимум ActiveX, и только встроенных, работоспособен без WMI, под WSH x86/x64.
• Достаточная функциональность и удобство важнее быстродействия и паттернов.

Легкая версия 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).

В прикрепленных к посту скриптах демонстрируется работа на примере абстрактной задачи: для каждого символа из строки letters создаются отдельные процессы, каждый в цикле помещает свой символ в буфер, по мере заполнения которого другой процесс выводит по 3 "слова" в консоль. Для WScript консоль сымитирована окном IE. Попутно выводятся запущенные и остановленные процессы ОС (в примере используется WMI, но для функционирования механизма он не обязателен).
В ходе дебага у меня накопились некоторые наблюдения и комменты, кои я выложу, если будет спрос - дело в том, что потребуется время, чтобы привести их в читабельный вид. Конструктивная критика приветствуется.

Post's attachments

mproclite_letters.zip 6.78 kb, 7 downloads since 2013-08-10 

You don't have the permssions to download the attachments of this post.
Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

93

Re: WSH: обмен данными и объектами между скриптами — 2

omegastripes
Объясните значение термина "индокод"?

( 2 * b ) || ! ( 2 * b )

94

Re: WSH: обмен данными и объектами между скриптами — 2

Видимо, это ирония на тему Индусский код

WBR. Roman

95

Re: WSH: обмен данными и объектами между скриптами — 2

2 Rumata
Да, Rom5 абсолютно прав. После дебага, когда практически все было готово, я полистал скрипт - местами отсвечивал индусский код. Например, вот строчка:

executeglobal "sub " & handlername & "(" & vars & "): process." & handlername & " " & vars & ": end sub"

Но, поскольку скрипт выполняет свою функцию достаточно стабильно, решил опубликовать.

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

96 (изменено: teadrinker, 2017-03-03 19:25:06)

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon, а как второй скрипт узнает, что какое-то user-defined свойство объекта изменилось и нужно считывать значение? Нужно подключиться к DWebBrowserEvents2. На AHK реализуется через ComObjConnect():

#Persistent
#SingleInstance, Off
DetectHiddenWindows, On
param = %1%

myContainer := new GlobalContainer("storage")

if param  {  ; это будет происходить во втором скрипте
   myContainer.Connect(Func("WatchProperties"))
}
else  {   ; это будет происходить в главном скрипте
   Run, "%A_AhkPath%" "%A_ScriptFullPath%" "1",,, PID
   OnExit(Func("Exit").Bind(myContainer, PID))
   
   WinWait, ahk_pid %PID%
   myContainer.arr1 := {key1: "Первое значение"}
   myContainer.arr2 := {key2: "Второе значение"}
   ExitApp
}

WatchProperties(obj, prop)  {
   key := prop = "arr1" ? "key1" : "key2"
   MsgBox,, Сообщение от второго скрипта:, % obj[prop][key]
}

Exit(obj, PID)  {
   obj.Quit()
   WinClose, ahk_pid %PID%
}

class GlobalContainer  {
   __New(name)  {
      for wnd in ComObjCreate("Shell.Application").Windows  {
         if (wnd.GetProperty("container_name") = name)
            this._obj := wnd
      }
      if !this._obj  {
         this._obj := ComObjGet("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
         this._obj.PutProperty("container_name", name)
      }
   }
   
   __Set(prop, value)  {
      if prop not in _obj,_userFunc
         Return this._obj.PutProperty(prop, value)
   }
   
   __Get(prop)  {
      if (prop != "_obj")
         Return this._obj.GetProperty(prop)
   }
   
   Connect(userFunc)  {
      this._userFunc := userFunc.Bind(this)
      ComObjConnect(this._obj, this)
   }
   
   PropertyChange(prop, obj)  {
      this._userFunc.Call(prop)
   }
   
   Quit()  {
      this._obj.Quit()
   }
}

Интересно, что пока обработка события во втором скрипте не завершена, поток первого не продолжается.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

97 (изменено: Xameleon, 2017-03-03 19:59:01)

Re: WSH: обмен данными и объектами между скриптами — 2

teadrinker, неужели эта тема ещё актуальна ? @_@. Не ожидал. ) Ну что ж, хорошо, что развитие не заброшено.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

98

Re: WSH: обмен данными и объектами между скриптами — 2

А её я только заметил.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

99

Re: WSH: обмен данными и объектами между скриптами — 2

Xameleon пишет:

2 JSman: От слов к действиям. Есть что посмотреть ?

Чуток опоздал с ответом, на 6 лет, но в рамках скриптовой модели никак не сделаешь  потоки. Один процесс приравнивается одному потоку и только так.

Что касается хака с событием присвоения, то есть замечательная старая и забытая тема с геттерами и сеттерами.

100

Re: WSH: обмен данными и объектами между скриптами — 2

Нужно создать объект ADODB.Recordset, в который смогут добавлять записи несколько скриптов, запущенных в отдельных процессах.
Попробовал передать с помощью GlobalContainer ссылку на экземпляр объекта ADODB.Recordset, созданного в первом скрипте, во второй скрипт. Во втором скрипте видны все записи, созданные в первом до передачи ссылки. По идее, ссылка в обоих скриптах должна быть на один и тот-же экземпляр объекта ADODB.Recordset, но все записи, добавленные во втором скрипте, в первом не видны. Такое впечатление, что при получении ссылки во втором скрипте создается клон ADODB.Recordset. С другими объектами, например, FSO или Dictionary, такого не происходит. Для теста использован класс GlobalContainer из первого поста:

1 скрипт

Option Explicit

Const adUseClient = 3
const adUseServer = 2
Const adDouble = 5

Dim gCon, dict1, dict2, rs1, rs2
Set gCon = New GlobalContainer
gCon.Open "storage"
gCon.PutProperty "test", InputBox("Введите значение для глобальной переменной ""test"".")
Set dict1 = CreateObject("Scripting.Dictionary")
gCon.PutProperty "dict1", dict1
Set rs1 = CreateObject("ADODB.Recordset")
With rs1
	.Fields.Append "value", adDouble
	.CursorLocation = adUseServer
	.Open
	.AddNew
	.Fields("value") = 0
	.Update
	MsgBox "Скрипт 1, количество записей rs1 = " & .RecordCount
	gCon.PutProperty "rs1", rs1
	MsgBox "Запустите скрипт 2"
	.Update
	MsgBox "Скрипт 1, количество записей rs1 = " & .RecordCount
End With
Set rs2 = gCon.GetProperty("rs2")
Set dict2 = gCon.GetProperty("dict2")
With rs2
	MsgBox "Скрипт 1, количество записей rs2 = " & .RecordCount
End With
MsgBox "rs1 == rs2 " & (rs1 Is rs2)
MsgBox "dict1 == dict2 " & (dict1 Is dict2)

Class GlobalContainer
	
    Private wnd, owner
	
    Sub Open(name)
        For Each wnd in CreateObject("Shell.Application").Windows
            if Instr(1,wnd.GetProperty("container_name"), name) = 1 Then Exit Sub
        Next
        owner = True
        Set wnd = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        wnd.PutProperty "container_name", name
    End Sub
    
    Sub PutProperty(name, value)    
        wnd.PutProperty name, value
    End Sub
    
    Function GetProperty(name)
        On Error Resume Next
        if IsObject(wnd.GetProperty(name)) Then
            Set GetProperty = wnd.GetProperty(name)
        Else
            GetProperty = wnd.GetProperty(name)
        End if
    End Function
	
    Private Sub Class_Terminate()
        On Error Resume Next
        if owner Then wnd.Quit()
    End Sub
	
End Class

2 скрипт

Option Explicit

Dim gCon, dict1, rs1
Set gCon = New GlobalContainer
gCon.Open "storage"
MsgBox "Значение переменной ""test"": " & gCon.GetProperty("test") ,vbInformation
Set dict1 = gCon.GetProperty("dict1")
gCon.PutProperty "dict2", dict1
Set rs1 = gCon.GetProperty("rs1")
With rs1
	MsgBox "Скрипт 2, количество записей rs1 = " & .RecordCount
	.AddNew
	.Fields("value") = 1
	.Update
	MsgBox "Скрипт 2, количество записей rs1 = " & .RecordCount
	gCon.PutProperty "rs2", rs1
	MsgBox "Продолжите выполнение скрипта 1"
End With

Class GlobalContainer
	
    Private wnd, owner
	
    Sub Open(name)
        For Each wnd in CreateObject("Shell.Application").Windows
            if Instr(1,wnd.GetProperty("container_name"), name) = 1 Then Exit Sub
        Next
        owner = True
        Set wnd = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
        wnd.PutProperty "container_name", name
    End Sub
    
    Sub PutProperty(name, value)    
        wnd.PutProperty name, value
    End Sub
    
    Function GetProperty(name)
        On Error Resume Next
        if IsObject(wnd.GetProperty(name)) Then
            Set GetProperty = wnd.GetProperty(name)
        Else
            GetProperty = wnd.GetProperty(name)
        End if
    End Function
	
    Private Sub Class_Terminate()
        On Error Resume Next
        if owner Then wnd.Quit()
    End Sub
	
End Class

Вопрос к гуру: может кто сталкивался и знает, как "правильно" расшарить recordset нескольким скриптам?

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251