-
Кто б сомневался © (20.05.16 16:21) [0]Есть программа x32, которая умеет запускать скрипты vbs через COM - т.е. используются IActiveScript, IActiveScriptParse и IActiveScriptSite (больше ничего).
Сделал примерно как описано здесь:
http://www.delphikingdom.ru/asp/viewitem.asp?UrlItem=/helloworld/activescript.htm
Только без IActiveScriptSiteWindow.
Т.е. берем текст скрипта и кидаем его в IActiveScriptParse.ParseScriptText .
Vbs cкрипты работают на ура, но появилась одна проблема.
Если в vbs скрипте есть строчка
set xmlDoc = CreateObject("MSXML2.DOMDocument")
или
set xmlDoc = createobject("Microsoft.XMLDOM")
Это объект для парсинга xml файлов -
то такой скрипт в IActiveScriptParse.ParseScriptText валит всю программу по AV. Даже если в vbs файле одна эта строчка.
Никакого текста ошибки нет. Тупо AV по адресу.
Win XP и Win 10 - одно и то же.
Event Viewer - пусто.
НО, если этот же vbs скрипт запустить в Windows (напр. через cmd.exe), то все проходит замечательно - никаких ошибок - объект создается и работает, отдавая данные по xml файлу. Проблема почему-то только с COM.
Если кто-нибудь использует IActiveScriptParse.ParseScriptText вы не могли бы проверить у себя, будет ли работать vbs со строчкой set xmlDoc = CreateObject("MSXML2.DOMDocument") .
Я пробовал и Msxml2.DOMDocument.6.0 и Msxml2.DOMDocument.3.0 - тоже самое.
Вот к примеру полный скрипт для проверки vbs:
Set objDoc = CreateObject("MSXML.DOMDocument")
objDoc.Load "d:\Test.xml"
Set objRoot = objDoc.documentElement
s = ""
t = ""
For Each child in objRoot.childNodes
s = s & child.getAttribute("name") & " "
Next
'wScript.echo(s) ' Displays "alpha beta gamma "
xml:
<?xml version="1.0"?>
<root>
<property name="alpha" value="1"/>
<property name="beta" value="2"/>
<property name="gamma" value="3"/>
</root>
Спасибо, чес. говоря даже не знаю что делать... -
iop © (20.05.16 16:36) [1]Вот так если не работает из под cmd,
то дело в битности сриптера, оси и самих активиксов
c:\windows\SysWOW64\WScript.exe your.vbs -
Кто б сомневался © (20.05.16 16:51) [2]iop © (20.05.16 16:36) [1]
Работает... :(
А вот vbs скрипт, состоящий из одной строчки:
set xmlDoc = CreateObject("MSXML2.DOMDocument")
или
set xmlDoc = createobject("Microsoft.XMLDOM")
если его всунуть в
IActiveScriptParse.ParseScriptText
дает Access Violation.
причем что на Win XP x64, что на Win 10 x64 - одно и то же. -
iop © (20.05.16 17:09) [3]а в чем вообще надобность запускать vbs из под обертки а не через createprocess?
или вообще обойтись только vbs или только delphi? -
Кто б сомневался © (20.05.16 17:09) [4]В примере Step2 этот код работает.
http://www.delphikingdom.ru/asp/viewitem.asp?UrlItem=/helloworld/activescript.htm
Значит где-то я налажал.
В чем же может быть проблема, вроде все так же создается .. и другой vbs код работает.. -
Кто б сомневался © (20.05.16 17:13) [5]Да еще один момент, этот IActiveScriptParse код работает в dll, в котором не используются формы может в этом проблема?
-
iop © (20.05.16 17:14) [6]Set objDoc = CreateObject("MSXML.DOMDocument")
objDoc.Load "d:\Test.xml"
set objDoc = CreateObject("MSXML.DOMDocument")
objDoc.async = false
if objDoc.Load "d:\Test.xml" then
....
else
MsgBox("kyky!")
end if -
iop © (20.05.16 17:17) [7]я бы еще кодировку самого файла скрипта проверил
-
Кто б сомневался © (20.05.16 18:43) [8]Нашел в чем была проблема.
Пожалуйста объясните почему так происходит... Я не понял..
TScriptEngine = class(TInterfacedObject, IActiveScriptSite)
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
function TScriptEngine._AddRef: Integer;
begin
Result := -1;
end;
function TScriptEngine._Release: Integer;
begin
Result := -1;
end;
При вызове fEngine.SetScriptSite(Self);
выполняется AddRef.
При вызове ParseText выполняется еще один _AddRef
Дальше от скрипта приходит OnEnterScript
А потом сразу же вызывается деструктор TScriptEngine
Никаких _Release не приходило.
Вот с чем это связано я так и не понял.
Убрал AddRef Addrealese и все заработало. Деструктор не вызывается.
Причем с другими vbs скриптами раньше все работало с отключенным механизмом подсчета ссылок (мне бы без него сделать..) -
Кто б сомневался © (20.05.16 19:21) [9]Вобщем нельзя так делать. Всмысле наследоваться от TInterfacedObject и писать собственные function _AddRef: Integer; stdcall; function _Release: Integer; stdcall;
Если нужно отключить счетчик ссылок, нужно наследоваться от TObject и там реализовывать уже собственные
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
Что я и сделал сейчас.
А оказывается QueryInterface вызывает GetInterface из TObject и там при определенных услвиях происходит тот самый IInterface(Obj)._AddRef (в моем случае вызывается уже TInrefacedObject.addRef, а не мой addRef). А потом в других методах выполняется и _Release из TinterfacedObject а там уже и деструктор.
Такие дела.. -
iop © (20.05.16 19:43) [10]почему нельзя-то?
если наследником intfobj планируется пользоваться в стиле обычного tobject (с намерением потом явно удалить ), то _addRef позволяет не бояться счетчика ссылок.
не умрет пока сам не кильнешь -
Кто б сомневался © (20.05.16 23:08) [11]
> op © (20.05.16 19:43) [10]
>
> почему нельзя-то?
>
> если наследником intfobj планируется пользоваться в стиле
> обычного tobject (с намерением потом явно удалить ), то
> _addRef позволяет не бояться счетчика ссылок.
> не умрет пока сам не кильнешь
Ну тогда у вас скоро будут такие же вопросы как у меня этот - случайные хрен пойми AV.
Я тоже так думал, и тоже пользовался им в стиле TObject - и все нормально работало, пока не настал этот случай.. У меня сейчас нету времени делать детальный анализ, сроки горят:
В случае если наследоваться от TInterfacedObject, то там RefCount при определенных условиях (я не знаю что это за условия, может знатоки объяснят) инкриминируется через TObject - IInterface(Obj)._AddRef;function TObject.GetInterface(const IID: TGUID; out Obj): Boolean;
var
InterfaceEntry: PInterfaceEntry;
begin
Pointer(Obj) := nil;
InterfaceEntry := GetInterfaceEntry(IID);
if InterfaceEntry <> nil then
begin
if InterfaceEntry^.IOffset <> 0 then
begin
Pointer(Obj) := Pointer(PByte(Self) + InterfaceEntry^.IOffset);
if Pointer(Obj) <> nil then IInterface(Obj)._AddRef; <<<<<<<<<<
end
else
IInterface(Obj) := InvokeImplGetter(Self, InterfaceEntry^.ImplGetter);
end else if ObjCastGUID = IID then
Pointer(Obj) := Pointer(Self);
Result := Pointer(Obj) <> nil;
end;
Т.е. обычно выполняется код end else if ObjCastGUID = IID then. А в каких то редких условиях выполняется тот что стрелкой показан.
Это вызовет метод TInterfacedObject.addref - который увеличит счетчик с нуля на еденицу. Дальше выполняется какой то сторонний код, на стороне COM и потом уже отладчик показывает точку останова на _Release TInterfacedObject. Т.е. не _Release моего класса, который наследован от TInterfacedObject, а именно TInterfacedObject.
Ну а дальше уже оттуда вызывается деструктор.
В остальных вариантах (в большинстве случаев) код выполняется в моих Addref и Release. -
iop © (20.05.16 23:27) [12]тоже так думал, и тоже пользовался им в стиле TObject - и все нормально работало
все там нормально с адреф.
но просто есть особенности реализации конкретных классов.
например TXMLDocument.
если в конструктор передан живой оунер (например он сброшен в дизайнере на форму) - поведение будет объектное.
если же в конструктор пришел нил в качестве оунера - будет интерфейсное поведение.
и тут уже следить за ссылками и не вызывать free