Текущий архив: 2003.10.02;
Скачать: CL | DM;
Вниз
COM. Правильная инициализация/закрытие Найти похожие ветки
← →
_VaaL_ (2003-09-12 10:19) [0]Где правильно прописывать методы инициализации/закрытия при создании COM компонента? Не хотелось бы вызывать дополнительные собственные методы Init и Close. Хотелось бы чтобы при создании обьекта он сам себя инициализировал. Какие методы перекрывать / куда что дописывать? (Instancing - Multiple instance, Threading Model - Single).
Спасибо
← →
Nikolay M. (2003-09-12 10:28) [1]Мнээ...
Секции initialization/finalization не подходят?
← →
_VaaL_ (2003-09-12 10:38) [2]А это будет правильно?
DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer - то функции которые нужны для работы обьекта. Насколько я понимаю обект еще не создан когда библиотека загружена. Обьект создает TAutoObjectFactory.
Насколько я понимаю поочередность загрузки такова:
1. Загружается DLL
2. INITIALIZATION
3. TAutoObjectFactory.Create
Выгрузка:
1. Освобождение Обьекта.
2. FINALIZATION.
Если я прав то initialization/finalization не подходят, если нет - буду рад если меня поправят.
← →
_VaaL_ (2003-09-12 11:49) [3]Оказывается, если использовать разделы initialization/finalization, то компиляция проэкта проходит без проблем, а вот регистрация - вылетает. Посему вопрос появляется еще один - почему?
← →
icWasya (2003-09-12 12:10) [4]а что значит - сам себя инициализировал?
вообще говоря есть метод Initialize - именно он вызывается при создании COM объекта. а для уничтожения - обычный Destroy
или надо что-то ещё ??
← →
_VaaL_ (2003-09-12 12:14) [5]Тоесть для инициации моих переменных мен нужно перекрыть Initialize и Destroy? Счас попробую...
← →
icWasya (2003-09-12 12:18) [6]и не забывай про inherited
← →
_VaaL_ (2003-09-12 12:26) [7]
procedure TСlassName.Initialize;
begin
inherited Initialize;
MyUnit.Init;
end;
Destructor TСlassName.Destroy;
begin
MyUnit.Quit;
inherited Destroy;
end;
Пишет Catastrophic Failure :(
← →
_VaaL_ (2003-09-12 12:33) [8]Теперь этот обьект даже создаватся нормально не может. Очень неохота выводить процедуры инициализации/закрытия в отдельные методы COM обьекта.
Идеальный вариант:
x:=CreateComObject(CLASS_Blablabla) as IBlablabla; // все уже инициировано можна приступать к работе
....
x:=NIL; // обьект освобожден, память под переменные - тоже
еще добавлю что процедуры моего модуля стопроцентно рабочие так как тестировались в отдельном проэкте.
← →
Юрий Федоров (2003-09-12 12:40) [9]>>procedure TСlassName.Initialize;
override не забыл ?
Если не забыл, то написано все правильно
← →
_VaaL_ (2003-09-12 12:52) [10]>>Юрий Федоров ©
>>override не забыл ?
Не забыл.
Нащет перекрытия Initialize - это стандартный прием в COM-програмировании или просто совет навскидку?
← →
icWasya (2003-09-12 13:08) [11]совет на основе личного опыта и анализа исходников VCL
а по-подробнее, что именно делается в MyUnit.Init ??
← →
_VaaL_ (2003-09-12 13:19) [12]В MyUnit.Init создается обект DOMDocument для загрузки определенных данных в динамический массив из XML документа.
var
XML: Variant;
...
XML:=CreateOLEObject("Msxml2.DOMDocument");
XML.Async:=false;
XML.Load(s);
...
Загрузка данных в динамический массив
...
XML:=varNULL; //освобождение обьекта DOMDocument
После этого массив сортируется для более быстрого поиска. Вот и все.
Еще одна процедура освобождает память динамического массива и должна вызыватся в конце.
Вот терерь это все нада всунуть в разделы инициализации/освобождения COM обьекта.
← →
Юрий Федоров (2003-09-12 13:35) [13]MyUnit.Init, вызванный сам по себе (не в инициализации COM-объекта), не приводит к падению?
Если так, то возможно собака порылась где-то в CoInitFlags
← →
_VaaL_ (2003-09-12 13:46) [14]Нет, не приводит. Я модуль MyUnit тестировал в отдельном приложении до токо как писать COM обьект.
Фабрика класов создает мой обьект так :
TAutoObjectFactory.Create(ComServer, TMyCOMComponent, Class_Blablabla, ciMultiInstance, tmSingle);
Может я использую неправильную модель? (хотя врядли..). Поидее CoInitFlags устанавливается в зависимости именно от этой команды (так хелп говорит).
← →
_VaaL_ (2003-09-12 15:24) [15]А в ответ тишина... :)
← →
Nikolay M. (2003-09-12 15:56) [16]
> var
> XML: Variant;
- глобальная переменная или она принадлежит СОМ-объекту?
Если первое, то хочется напомнить свой первый пост :)
Если второе - то будет ли происходить Catastrophic failure, если закомментировать MyUnit.Init/MyUnit.Quit?
← →
nikkie (2003-09-12 15:57) [17]ты вызов своего Init поставь под try...except
← →
Юрий Федоров (2003-09-12 15:59) [18]кроме того
1. Создается ли COM-объект (я так понял, что имеем дело с InProc Server) в основном потоке приложения или в дополниьельном.
2. С какими параметрами происходит вызов CoInintializaEx в вызывающем приложении (для этого потока)
← →
_VaaL_ (2003-09-12 16:16) [19]XML - локальная перменная процедуры Init. Тоесть первое отпадает. А вот второе - ничего непадает, если обьект не инициализируется в методе Initialize, хотя если запускать в другом проэкте то процедура Init работает нормально... странно.
← →
_VaaL_ (2003-09-12 16:23) [20]Я закоментировал секцию работы с XML - инициация прошла успешно (покрайней мере без видиміх проблем). Значит я неправильно работаю с XML. Выше я приводил пример инициации COM обьекта DOMDocument. Я что, создаю/удаляю его неправильно?
var
XML: Variant;
...
XML:=CreateOLEObject("Msxml2.DOMDocument");
XML.Async:=false;
XML.Load(<filename>);
...
XML:=varNULL;
← →
Polevi (2003-09-12 16:27) [21]>_VaaL_ (12.09.03 16:23) [20]
возможно плохой xml документ, парсер предоставляет информацию об ошибках парсинга, проверь
← →
Юрий Федоров (2003-09-12 16:29) [22]Отладчик не работает?
Какой-то Exception поднимается при работе с XML, только и всего. Если узнать, какой именно - все сразу станет ясно
← →
Nikolay M. (2003-09-12 16:30) [23]А в коде выше еще написана какая-то "Загрузка данных в динамический массив" - там что?
← →
_VaaL_ (2003-09-12 16:38) [24]>>Юрий Федоров © (12.09.03 16:29) [22]
Отладчик не работает?
Да в том то и дело что при использовании в любом другом проекте ексепшенов нету :(. А как я могу отладить DLL пошагово? - вроде никак. :(
Nikolay M. © (12.09.03 16:30) [23]
А в коде выше еще написана какая-то "Загрузка данных в динамический массив" - там что?
Простой разбор XML, установка размера для динамического массива и заполнение данными из XML документа
← →
_VaaL_ (2003-09-12 16:43) [25]Polevi © (12.09.03 16:27) [21]
не может он быть ошибочным так как открывается через експлорер. DTD схем нету.
← →
Nikolay M. (2003-09-12 16:55) [26]
> Простой разбор XML, установка размера для динамического
> массива и заполнение данными из XML документа
А если это все закомментировать?
Если все ок, тогда правы
> Polevi © (12.09.03 16:27) [21]
> Юрий Федоров © (12.09.03 16:29) [22]
← →
_VaaL_ (2003-09-12 16:59) [27]Nikolay M. © (12.09.03 16:55) [26]
Я коментировал. И все работало хорошо. Но тогда почему та же процедура без проблем работает в отдельном проэкте (никаких ексепшенов)?
← →
Nikolay M. (2003-09-12 17:07) [28]А код большой?
Кинь сюда, неохота на кофейной гуще гадать :)
← →
_VaaL_ (2003-09-12 17:21) [29]
type
TStoredProc = record
Name: string;
Params: array of string;
Request: string;
end;
var
SP: array of TStoredProc;
....
....
XML:=CreateOLEObject("Msxml2.DOMDocument");
XML.Async:=false;
XML.Load(s);
Root:=XML.DocumentElement;
if Root.HasChildNodes then
begin
Count:=Root.ChildNodes.Length;
SetLength(SP, Count);
for i:=0 to Root.ChildNodes.Length - 1 do
begin
SPNode:=Root.ChildNodes.Item(i);
SP[i].Name:=SPNode.NodeName; // Getting Name
SPParams:=SPNode.ChildNodes.Item(0); // Getting Parameters
if SPParams.HasChildNodes then
begin
Count:=SPParams.ChildNodes.Length;
SetLength(SP[i].Params, Count);
for j:=0 to SPParams.ChildNodes.Length - 1 do
begin
SPPar:=SPParams.ChildNodes.Item(j);
SP[i].Params[j]:=SPPar.NodeName;
end;
end;
SPParams:=SPNode.ChildNodes.Item(1); // Getting Request
SPPar:=SPParams.ChildNodes.Item(0);
if SPPar.NodeType = 4 /*CDATA*/ then
SP[i].Request:=SPPar.NodeValue;
end;
end;
XML:=varNULL; // Closing XML Object
Здесь:
XML, Root, SPNode, SPPar: Variant;
SP - структура которая заполняется из XML
Пример XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<test>
<params>
<id/>
<name/>
</params>
<request>
<![CDATA[Select <[name]> from Main_Menu where mm_id=<[id]>;]]>
</request>
</test>
</root>
← →
Nikolay M. (2003-09-12 17:25) [30]Хм. Сразу бросается в глаза, что TStoredProc - имя уже объявленного класса в DBTables... Этот модуль нигде не подключается?
← →
_VaaL_ (2003-09-12 17:27) [31]Nikolay M. © (12.09.03 17:25) [30] нет. Здесь вообще нет подключения к какой бы то нибыло БД
← →
Erik (2003-09-12 18:13) [32]"А как я могу отладить DLL пошагово? - вроде никак. :("
Если это без проблем отлаживается! Идем в Run/Parametrs
Там заполняем Host Application - кот вызывает твою dll.
И отлаживай себе на здорове. Но если проблема серездная, то врядли тебе здесь ответят. Com вобще дело темное.
← →
Юрий Федоров (2003-09-12 18:13) [33]Насчет отладчика - можно отлаживать DLL без проблем.
после помещения Exe и DLL в одну группу проектов и перебилда обоих отладчик ходит насквозь...
я на 90 процентов уверен, что дело в каком-то конфликте, связанном с флагами инициализации COM (конфликт поточных моделей).
Ты не пробовал поставить ThreadingModel = tmApartment?
В общем, один запуск прорраммы подл отладчиком - и ответ на вопрос будет получен...
← →
Serginio666 (2003-09-12 18:55) [34]Помоему сам нарывался на ThreadingModel = tmApartment. Работает только в TComponentFactory. Да и для DLL это не играет роли если не нужен маршалинг.
Лучше поставь проинициализируй как MTA, т.к. c STA куча проблем.
← →
Юрий Федоров (2003-09-12 19:04) [35]>>Serginio666 (12.09.03 18:55) [34]
С апартаментами проблемы только с Local Server, с InProc все должно быть нормально.
Да и лечится легко, путем небольшого потомка от фабрики классов...
← →
Serginio666 (2003-09-12 19:25) [36]Это я знаю, сам создавал,проверял. Да и для Inproc сервера ThreadingModel = tmApartment не играет никакой роли без TApartmentThread передается прямая ссылка на объект.
Может проблема в
http://www.rsdn.ru/article/atl/atlsingleton.xml
"Проблема маршалинга синглтона в фабрике классов также весьма актуальна для внутрипроцессных серверов, так как клиенты запросто могут находиться в разных апартаментах, и все клиенты будут получать прямую ссылку на синглтон. Для синглтонов с потоковой моделью Apartment это может означать, что вызовы могут приходить из других потоков. Без синхронизации все закончится плачевно, а клиенты даже не будут ничего подозревать, так как имеют дело не с proxy, а с прямым указателем, и ошибку RPC_E_WRONGTHREAD, означающую, что вызов был сделан из “неподходящего” потока, им никто не вернет."
← →
Serginio666 (2003-09-12 19:52) [37]Да еще очень плохо работать в СОМ с глобальными переменными.
Разве нельзя
Внести все в объект и работать с полем объекта.
procedure TСlassName.Initialize;
begin
inherited Initialize;
XML:=CreateOLEObject("Msxml2.DOMDocument");
end;
Destructor не нужен.
← →
_VaaL_ (2003-09-17 13:51) [38]Короче, помудрил я и понял, что всетаки проблема тут в создании Msxml2.DOMDocument такое впечатление что когда я вызываю CreateOLEObject("Msxml2.DOMDocument") то еще небыла вызывана CoInintialize, хотя модуль ComObj стоит в Uses...
Поэтому решил хранить загружаемые данные в простых файлах. После этого все начало работать без проблем.
Спасибо всем кто помогал разбиратся с этим делом.
← →
Erik (2003-09-18 14:37) [39]А я то думаю, чего у меня глючит завершение InProc сервера! ThreadingModel = tmApartment стоит хотел поменять да так и оставил. А маршалинг у меня есть и выгружается коректно только в случаее с Exe сервером.
Страницы: 1 вся ветка
Текущий архив: 2003.10.02;
Скачать: CL | DM;
Память: 0.54 MB
Время: 0.01 c