События динамических объектов

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
hclubmk
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 240
Зарегистрирован: 19.06.2009 (Пт) 14:23
Откуда: От-туда

События динамических объектов

Сообщение hclubmk » 13.12.2010 (Пн) 12:47

Существует массив динамически созданных (не однотипных, заранее неизвестных) контролов, описанный как ECArray() As VBControlExtender
Каким образом можно обабатывать поднимаемые события каждого из элементов массива, и вообще, будет ли корректен такой путь организации работы с множеством EC?
Научились ли Вы радоваться трудностям?

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: События динамических объектов

Сообщение Antonariy » 13.12.2010 (Пн) 14:04

Каким образом можно обабатывать поднимаемые события каждого из элементов массива, и вообще, будет ли корректен такой путь организации работы с множеством EC?
Конечная цель этого пути неизвестна, чего уж говорить о его корректности. Если цель — ловить события неизвестных контролов, то она недостижима никаким путем (кроме событий MouseMove, KeyPress и т.п. — через сабклассинг). Они должны быть известны, либо должен быть известен и им и программе какой-то интерфейс-переходник, поддерживающий нужный функционал.
Лучший способ понять что-то самому — объяснить это другому.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: События динамических объектов

Сообщение Хакер » 13.12.2010 (Пн) 14:58

Antonariy писал(а):Если цель — ловить события неизвестных контролов, то она недостижима никаким путем


Ложь. Если речь идёт об ActiveX-контролах, то события неизвестного контрола прекрасно можно отловить. Надо только знать, как.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

hclubmk
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 240
Зарегистрирован: 19.06.2009 (Пт) 14:23
Откуда: От-туда

Re: События динамических объектов

Сообщение hclubmk » 13.12.2010 (Пн) 15:26

Antonariy писал(а):кроме событий MouseMove, KeyPress и т.п. — через сабклассинг

EC_ObjectEvent(Info As EventInfo) ловит события. Сценарий и методы обрабротки - вопрос интересный, но пока не о нем речь.
Что посоветуете? Реализовывать массив контролов-контейнеров, каждый элемент которого бутет содержать один-единственный WithEvents EC (события которого можно ловить), или есть путь проще?
Научились ли Вы радоваться трудностям?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: События динамических объектов

Сообщение Хакер » 13.12.2010 (Пн) 15:37

hclubmk писал(а):есть путь проще?

Есть другой путь. Без VBControlExtender и WithEvents.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

hclubmk
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 240
Зарегистрирован: 19.06.2009 (Пт) 14:23
Откуда: От-туда

Re: События динамических объектов

Сообщение hclubmk » 13.12.2010 (Пн) 16:24

Хакер писал(а):другой путь

1) другой не значит проще?
2) какой?
Научились ли Вы радоваться трудностям?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: События динамических объектов

Сообщение Хакер » 13.12.2010 (Пн) 20:30

1) Хум хау.
2) Обработка событий COM-объектов — не какой-то там сверхсекретный, а вплоне открытый и документированный механизм.

Любой ActiveX-контрол предоставит тебе интерфейс IConnectionPointContainer. Этот интерфейс служит для работы с конекшен-поинтами. Оные являются call-хабами и рассылают уведомление (а проще говоря — делают вызов обработчика) о событии всем, кто подписался на такие уведомления.

Так вот, ты запрашиваешь IConnectionPointContainer и вызываешь метод FindConnectionPoint, передав IID sink-интерфейса, который принимает уведомления о событиях данного контрола. Такой интерфейс для неизвестного ActveX-контрола надо найти в его библиотеке типов, которая у любого контрола заведомо вшита прямо в нём. Искать tlb-файл не нужно: контрол предоставляет интерфейс IProvideClassInfo, через который можно можно получить типоописание CO-класса, перебрать его интерфейсы и найти среди них sink-интерфейс (и его IID). Нужный интерфейс будет иметь установленные Impl-флаги IMPLTYPEFLAG_FSOURCE и IMPLTYPEFLAG_FDEFAULT.

Вызвал ты, значит, FindConnectionPoint, она тебе возвращает интерфейсный указатель на IConnectionPoint.

У IConnectionPoint надо вызвать метод Advise, и этим самым подписаться на получение уведомлений о событиях. Метод вернёт слепок (cookie), который потом надо передавать для отписки, вызывая метод Unadvise.

В метод Advise надо передать указатель на свой объект, который бы реализовывал sink-интерфейс.

Понятно, что раз конкретный контрол заранее неизвестен, заранее написать класс, который бы заведомо реализовывал нужный sink-интерфейс — невозможно.
Но есть одно но: sink-интерфейс — это disp-интерфейс, поэтому должны быть реализованными только IDispatch-методы.
А теперь магия: вместо такого объекта ты делаешь лжеобъект: то есть в модуле создаёшь массив, который будет играть роль VTable, и в него заносишь адреса функций, выполняющих роль реализаций методов IDispatch-а. Самый интересный метод для тебя: Invoke.

Когда есть неизвестные контролы, события которых надо ловить, ты всем им в качестве event-sink-а назначаешь (вызовом Advise) свой лжеобъект. Когда события возникают, будет вызван твой метод Invoke, которому будут переданы все параметры, если такие у события есть.

В общем, можно сделать один вечноживущий sink-объект, который будет поддерживать все sink-интерфейсы для любого контрола, и в этом случае можно сделать пустые AddRef/Release. Можно сделать реальные вручную реализованные sink-объекты, с контролем времени жизни.

Первый вариант (вечноживущий объект, реализующий динамический набор интерфейсов) гибче, но нарушает регламент COM (набор поддерживаемых интерфейсов объекта должен быть постоянным в течение всего времени жизни объекта). Второй более походит на VBControlExtender, но с гораздом меньшим числом посредников.

А по сути это ручная реализация того, что делается автоматически при использовании WithEvents и/или VBControlExtender.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

NashRus
Постоялец
Постоялец
 
Сообщения: 388
Зарегистрирован: 18.03.2006 (Сб) 1:16

Re: События динамических объектов

Сообщение NashRus » 14.12.2010 (Вт) 4:42

2hclubmk

hclubmk писал(а):Что посоветуете? Реализовывать массив контролов-контейнеров, каждый элемент которого бутет содержать один-единственный WithEvents EC (события которого можно ловить), или есть путь проще?


Это реально самый простой путь.

Update: только не массив контролов-контейнеров, а массив объектов-контейнеров.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot, Yandex-бот и гости: 76

    TopList