Как правильно написать заполнение событий в объекте WbemScripting.SWbemSink чрез Invoke

программирование C++ Delphi VBScript OLE Automation

Подойдет пример на Delphi C++, но разберусь с любым языком. Важно только какие параметры передавать.
Просьба дочитать текст вопроса до конца или не отвечать вовсе.

В моей программе встроена поддержка скриптов Microsoft ® Windows Script Host, которые работают через механизм OLE Automation (этот момент определяющий).

Запускается все это стандартно:

ScriptControl := CreateOLEObject('MSScriptControl.ScriptControl');
with (ScriptControl as IScriptControl) do begin
Language := 'VBScript';
Script.ExecuteStatement(" ...

где IScriptControl импортируетс из MSScriptControl_TLB C:\Windows\system32\msscript.ocx
и IWshShell3 (WScript.Shell) подтягивается из "IWshRuntimeLibrary", файла wshom.ocx

Как Вам известно, в скриптах запускаемых интерпретатором wscript.exe из файлов объект "WScript" обладает замечательным методом CreateObject. Этот метод выполняет две задачи: создает объект "WbemScripting.SWbemSink" и привязывает к его событиям процедуры из сценария (скрипта).

Грубо говоря, следующий код создает объект objSink и устанавливает его свойству OnObjectReady процедуру Sink_OnObjectReady. Далее процедура Sink_OnObjectReady может быть задействована в асинхронном вызове.

Set objSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")

Sub Sink_OnObjectReady(OutParams, objAsyncContext)
End Sub

В режиме OLE Automation метода WScript.CreateObject (как и много чего еще). Но её можно написать в основном теле программы из которой выполняется скрипт и добавить в скрипт.

Подобная функция написана в autoit
"ObjEvent" - Обрабатывает поступающие события от указанного объекта.

Решение этой задачи на autoit выглядит так:

$Sink = ObjCreate("WbemScripting.SWbemSink")
ObjEvent($Sink , "SINK_")
Func SINK_OnObjectReady($objEvent, $objAsyncContext)
EndFunc

Собственно в чем затык с Windows Script Host:

В основной программе через ScriptControl.Procedures.Item[N] доступна любая процедура в виде IScriptProcedure = interface(IDispatch)
В самом скрипте есть доступ к IDispatch процедуры через штатную функцию GetRef("Sink_OnObjectReady")

Но похоже этот IDispatch надо установить в недоступное для редактирование свойство через вызов Invoke. Приведу отрывок WbemScripting_TLB, который меня к этому заключению привел:

unit WbemScripting_TLB;
...
// *********************************************************************//
// Interface: ISWbemSink
// Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID: {75718C9F-F029-11D1-A1AC-00C04FB6C223}
// *********************************************************************//
ISWbemSink = interface(IDispatch)
['{75718C9F-F029-11D1-A1AC-00C04FB6C223}']
procedure Cancel; safecall;
end;
...
// *********************************************************************//
// DispIntf: ISWbemSinkEvents
// Flags: (4240) Hidden NonExtensible Dispatchable
// GUID: {75718CA0-F029-11D1-A1AC-00C04FB6C223}
// *********************************************************************//
ISWbemSinkEvents = dispinterface
['{75718CA0-F029-11D1-A1AC-00C04FB6C223}']
procedure OnObjectReady(const objWbemObject: ISWbemObject;
const objWbemAsyncContext: ISWbemNamedValueSet); dispid 1;
procedure OnCompleted(iHResult: WbemErrorEnum; const objWbemErrorObject: ISWbemObject;
const objWbemAsyncContext: ISWbemNamedValueSet); dispid 2;
procedure OnProgress(iUpperBound: Integer; iCurrent: Integer; const strMessage: WideString;
const objWbemAsyncContext: ISWbemNamedValueSet); dispid 3;
procedure OnObjectPut(const objWbemObjectPath: ISWbemObjectPath;
const objWbemAsyncContext: ISWbemNamedValueSet); dispid 4;
end;
...

Кроме autoit эта задача решена ещё как минимум в 1 проекте, но они, увы, без исходных кодов.
Ответы:
нужно переопределить InvokeEvent у TOleServer, который реализует ISWbemSink
см. реализацию TSWbemSink по ссылке


10 лет назад

RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.

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

Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.