Глупый вопрос...
А что происходит, если при использовании COM объекта
сделать на один Release меньше, чем AddRef?
Понятно, что такие объкты висят до завершения работы программы.
А вот кто и как их потом прибивает и возможны
ли из-за этого проблемы типа access violation и прочих серьезных.
Вопрос возник из-за GUI, написанного на Borland Builder C++.
Этот самый GUI использует COM объект с методом, в который
передается другой COM объект ([in] параметр)
Так вот бормановские врапперы похоже вызывают на один Release
меньше, чем положено и в итоге имею кучу leak'ов.
P.S. Это кстати пример в тему почему BCB не стоит использовать
даже для написания простеньких COM клиентов.
Мне похоже даже с врапперами продется насильно вызывать Release.
Нафига блин нужны такие врапперы
Hello, !
You wrote on Thu, 17 Feb 2005 14:56:03 GMT:
> Глупый вопрос... > А что происходит, если при использовании COM объекта > сделать на один Release меньше, чем AddRef? > Понятно, что такие объкты висят до завершения работы программы.
> А вот кто и как их потом прибивает
ExitProcess прибивает. Впрочем, он не в курсе, что это именно COM-объекты.
Он все на свете прибивает.
> и возможны ли из-за этого проблемы типа access violation и прочих > серьезных.
Запросто.
With best regards, Sergey.
Posted via RSDN NNTP Server 1.9
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, <Аноним>, Вы писали:
А>Этот самый GUI использует COM объект с методом, в который А>передается другой COM объект ([in] параметр) А>Так вот бормановские врапперы похоже вызывают на один Release А>меньше, чем положено и в итоге имею кучу leak'ов.
да, тоже наступали на это дело, если передавать параметром указатель на интерфейс, дебилдер в реализации метода лепит вокруг него свою обертку и при заключении переданного указателя на интерфейс в эту обертку делает AddRef(), но в деструкторе обертки никаких Release() нету. Пришлось вставлять в каждый такой дебилдерный метод принудительный Release() для соблюдения баланса
Здравствуйте, Tom, Вы писали:
Tom>А у тебя случаем не кольцевая ссылка получется?
Нет. В этом смысле все чисто.
Прогнал BoundsChecker и во всех таких ситуациях показывается
стабильный leak с refCounter равный 1.
Все точно блин, как в аптеке, только не правильно
Re[2]: Как умирают повисшие объекты?
От:
Аноним
Дата:
17.02.05 15:59
Оценка:
Здравствуйте, Odi$$ey, Вы писали:
OE>Здравствуйте, <Аноним>, Вы писали:
А>>Этот самый GUI использует COM объект с методом, в который А>>передается другой COM объект ([in] параметр) А>>Так вот бормановские врапперы похоже вызывают на один Release А>>меньше, чем положено и в итоге имею кучу leak'ов.
OE>да, тоже наступали на это дело, если передавать параметром указатель на интерфейс, дебилдер в реализации метода лепит вокруг него свою обертку и при заключении переданного указателя на интерфейс в эту обертку делает AddRef(), но в деструкторе обертки никаких Release() нету. Пришлось вставлять в каждый такой дебилдерный метод принудительный Release() для соблюдения баланса
Блин, а у меня таких мест уже довольно много.
А вот BCB6 похоже генерит нормальные врапперы и как теперь писать
"портабельный" в мире дебилдера код?
Мало того, что принудительный Release() нужен,
так еще и в таком вот стиле.
Здравствуйте, Sergey, Вы писали:
S>Hello, ! S>You wrote on Thu, 17 Feb 2005 14:56:03 GMT:
>> Глупый вопрос... >> А что происходит, если при использовании COM объекта >> сделать на один Release меньше, чем AddRef? >> Понятно, что такие объкты висят до завершения работы программы.
>> А вот кто и как их потом прибивает
S>ExitProcess прибивает. Впрочем, он не в курсе, что это именно COM-объекты. S>Он все на свете прибивает.
>> и возможны ли из-за этого проблемы типа access violation и прочих >> серьезных.
S>Запросто.
Вот именно это у меня время от времени и происходит.
В самый последний момент, когда уже почти все выгружено,
иногда программа вываливается по access violation.
Может я конечно еще где косячу,
но BoundsChecker кроме ликов COM интерейсов ничего не показывает.
Здравствуйте, Аноним, Вы писали:
А>Глупый вопрос... А>А что происходит, если при использовании COM объекта А>сделать на один Release меньше, чем AddRef?
Объект будет утерян. И память которую он занимает уже никому не достанется. Кроме того — объект может заблокировать некие внешние ресурсы (файлы, сетевые подлючения и т.д.). Так же, в случае DLL-сервера, DLL (создавшую этот объект) не получится выгрузить из процесса — COM будет считать, что в ней есть активные объекты.
Естественно, что когда завершит работу основной процесс, ресурсы (контролируемые Windows) освободятся. (Это я на всякий случай написал)
Основной нюанс с который нужно учитывать при работе с VCL и COM-обектами — VCL выполняет деинициализацию COM до разрушения форм. Это я про то, что делается после выхода из WinMain.
Возможно это связано с порядком деинициализации внутренностей этой библиотеки. В результате получаешь смарт-указатель который указывает на адресное пространство выгруженной DLL. Но это проблема успешно решается.
>P.S. Это кстати пример в тему почему BCB не стоит использовать А>даже для написания простеньких COM клиентов.
Не, я думаю что тем кто задает такие вопросы лучше вообще c COM не связываться
Борманоские врапперы... реальные пацаны, понимающие природу и опасность COM-технологии, используют свои, которым доверяют на 100%. Своими же становятся всесторонне проверенные чужие. И у них все работает. Так что не будем тут пальцы гнуть.
Что не нравится мой комментарий? Ну дык лучше было держать свое мнение при себе
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: Как умирают повисшие объекты?
От:
Аноним
Дата:
17.02.05 20:12
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Здравствуйте, Аноним, Вы писали:
А>>Глупый вопрос... А>>А что происходит, если при использовании COM объекта А>>сделать на один Release меньше, чем AddRef?
КД>Объект будет утерян. И память которую он занимает уже никому не достанется. Кроме того — объект может заблокировать некие внешние ресурсы (файлы, сетевые подлючения и т.д.). Так же, в случае DLL-сервера, DLL (создавшую этот объект) не получится выгрузить из процесса — COM будет считать, что в ней есть активные объекты.
КД>Естественно, что когда завершит работу основной процесс, ресурсы (контролируемые Windows) освободятся. (Это я на всякий случай написал)
КД>Основной нюанс с который нужно учитывать при работе с VCL и COM-обектами — VCL выполняет деинициализацию COM до разрушения форм. Это я про то, что делается после выхода из WinMain.
И что это означает? Следует ли из этого,
что в деструкторах форм использовать COM объекты не рекомендуется?
КД>Возможно это связано с порядком деинициализации внутренностей этой библиотеки. В результате получаешь смарт-указатель который указывает на адресное пространство выгруженной DLL. Но это проблема успешно решается.
Как?
>>P.S. Это кстати пример в тему почему BCB не стоит использовать А>>даже для написания простеньких COM клиентов.
КД>Не, я думаю что тем кто задает такие вопросы лучше вообще c COM не связываться
Ну в таком случае тех, кто реализовал такие врапперы надо просто не допускать к компьютерам.
КД>Борманоские врапперы... реальные пацаны, понимающие природу и опасность COM-технологии, используют свои, которым доверяют на 100%. Своими же становятся всесторонне проверенные чужие. И у них все работает. Так что не будем тут пальцы гнуть.
tlbimp видимо тоже использовать крайне не рекомендуется
КД>Что не нравится мой комментарий? Ну дык лучше было держать свое мнение при себе
Да, мне твой комментарий не нравится.
Но если я высказал свое фи по поводу продукта,
который уже мертв именно из-за своих многочисленных проблем.
То ты наехал лично на меня.
Наверное ты из Борланда и писал эти самые врапперы
Я, кстати, совсем не спец в BCB.
Я отвечаю за COM сервер, который юзается борландовым клиентом.
С клиентами на васике и многих других языках проблем нету,
а в вот с борманом (причем похоже только 5-м) нужен особый подход.
Это достаточный повод для недовольства.
Здравствуйте, Аноним, Вы писали:
КД>>Основной нюанс с который нужно учитывать при работе с VCL и COM-обектами — VCL выполняет деинициализацию COM до разрушения форм. Это я про то, что делается после выхода из WinMain.
А>И что это означает? Следует ли из этого, А>что в деструкторах форм использовать COM объекты не рекомендуется?
Это означает то, что при разрушении объекта формы будут вызваны деструкторы смарт-указателей, которые вызовут Release для объектов из выгруженных DLL. Занавес.
КД>>Возможно это связано с порядком деинициализации внутренностей этой библиотеки. В результате получаешь смарт-указатель который указывает на адресное пространство выгруженной DLL. Но это проблема успешно решается.
А>Как?
CoInitialize/CoUnitialize в формах, которые живут до конца существования приложения.
Причем CoUnitialize должен вызываться после разрушения последнего смарт-указателя. Сия задача решается обертывание (в мокрую простыню ) этих двух вызовов в класс (конструктор-деструктор) и помещение этого объекта в первым членом в список членов класса.
Но, между нами девочками, я на это забивал и просто вставлял CoInitialize в начало WinMain
А>Ну в таком случае тех, кто реализовал такие врапперы надо просто не допускать к компьютерам.
Ну дык студенты, блин, писали.
А>tlbimp видимо тоже использовать крайне не рекомендуется
Никогда не пользовался.
А>Я отвечаю за COM сервер, который юзается борландовым клиентом. А>С клиентами на васике и многих других языках проблем нету,
Ну дык и написал бы для него нормальный враппер. Руками на С++. А не мышью через меню.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: Как умирают повисшие объекты?
От:
Аноним
Дата:
17.02.05 22:34
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Здравствуйте, Аноним, Вы писали:
КД>>>Основной нюанс с который нужно учитывать при работе с VCL и COM-обектами — VCL выполняет деинициализацию COM до разрушения форм. Это я про то, что делается после выхода из WinMain.
А>>И что это означает? Следует ли из этого, А>>что в деструкторах форм использовать COM объекты не рекомендуется?
КД>Это означает то, что при разрушении объекта формы будут вызваны деструкторы смарт-указателей, которые вызовут Release для объектов из выгруженных DLL. Занавес.
Забавно. Чем дальше в лес, тем толще партизаны.
КД>>>Возможно это связано с порядком деинициализации внутренностей этой библиотеки. В результате получаешь смарт-указатель который указывает на адресное пространство выгруженной DLL. Но это проблема успешно решается.
А>>Как? КД>CoInitialize/CoUnitialize в формах, которые живут до конца существования приложения.
КД>Причем CoUnitialize должен вызываться после разрушения последнего смарт-указателя. Сия задача решается обертывание (в мокрую простыню ) этих двух вызовов в класс (конструктор-деструктор) и помещение этого объекта в первым членом в список членов класса.
КД>Но, между нами девочками, я на это забивал и просто вставлял CoInitialize в начало WinMain
Наверное я тоже так же сделаю (CoInitialize в начало WinMain).
Хоть и не кошерно, но зато только в одном месте.
Здравствуйте, Odi$$ey, Вы писали:
OE>Здравствуйте, <Аноним>, Вы писали:
А>>Этот самый GUI использует COM объект с методом, в который А>>передается другой COM объект ([in] параметр) А>>Так вот бормановские врапперы похоже вызывают на один Release А>>меньше, чем положено и в итоге имею кучу leak'ов.
OE>да, тоже наступали на это дело, если передавать параметром указатель на интерфейс, дебилдер в реализации метода лепит вокруг него свою обертку и при заключении переданного указателя на интерфейс в эту обертку делает AddRef(), но в деструкторе обертки никаких Release() нету. Пришлось вставлять в каждый такой дебилдерный метод принудительный Release() для соблюдения баланса
Позволю не согласится.
В BCB5
Обертка, которая используется для передачи интерфейса генерится следующим образом
typedef TComInterface< <имя интерфейса>, <IID> > <имя интерфейса>Ptr
где
template <class T,
const IID *piid = &GUID_NULL> /* NOTE: The IID parameter is for backward-compatibility*/
/* New code should rely on __uuidof(intf) support */class TComInterface
{
public:
TComInterface() : intf(0)
{}
// NOTE: The default behaviour of the constructor is to not AddRef the interface
// pointer parameter. This is appropriate if the interface was obtained
// has already been addRef'ed - as when retrieving a Font property.
//
TComInterface(T* p, bool addRef = false)
{
if (((intf = p) != 0) && addRef)
intf->AddRef();
}
.....
TComInterface(const TComInterface<T, piid>& src)
{
if ((intf = src.intf) != 0)
intf->AddRef();
}
// NOTE: This assignment operator does *NOT* addRef the interface pointer being
// assigned to this object.
//
TComInterface<T, piid>& operator=(T* p)
{
Bind(p);
return *this;
}
TComInterface<T, piid>& operator=(const TComInterface<T, piid>& src)
{
if (src.intf != 0)
src.intf->AddRef();
Reset(src.intf);
return *this;
}
.....
void Reset(T* p = 0)
{
if (intf)
intf->Release();
intf=p;
}
~TComInterface()
{
Reset();
}
Видно, что Release() вызывается всегда.
Так что скорее должен вызываться лишний Release().