Re[6]: Вызов событий COM из разных потоков
От: Мизантроп  
Дата: 09.11.09 12:34
Оценка:
Здравствуйте, silart, Вы писали:

S>Внесем ясность.


Удачная мысль

S>Понятно, что конструктор вызывается другим (по отношению к отправляющему события) потоком.

S>Таким образом, pITypeInfo получается в конструкторе одним потоком, а используется в потоковой функции другим потоком. Нужно ли здесь использовать маршалинг? Ведь по идее должно было все обрушиться и при одном компоненте, а все работает.

Ну а с чего бы ему обрушаться Когда Вы просто передаёте куда-то интерфейс, без маршалинга, Вы фактически передаёте адрес таблицы в памяти, содержащей адреса методов, реаслизующих этот интерфейс. При этом вызов метода интерфейса — это просто самый обыкновенный вызов функции по адресу. Вы же не пишите в реализации каждого метода проверку валидности текущего апартамента и не генерите по этому поводу исключений, откуда же возьмётся обрушение? И никто этого не делает, потому что это не задача объекта. Это задача для прокси, и у него есть для этого необходимые средства. Когда Вы попытаетесь вызвать метод прокси из чужого для него апартамента, тот обратится за RPC буфером к менеджеру канала, а тот в ответ вернёт WRONG_THREAD. В случае же прямого вызова такой проверки сделать просто некому.

S>Мизантроп, если речь идет о компоненте без событий, то с STA все понятно. А как задать STA, если речь идет о генерации событий? Как задать STA именно для событийного потока явно?


Апартаментная модель для потока всегда задаётся одинаково — вызовом CoInitialize(Ex).
Потоковая модель клиента — это одно, а поддерживаемая сервером — другое, и они друг от друга не зависят. Каждый из них выбирает ту модель, которую считает для себя наиболее подходящей, и маршалинг как раз и служит для согласования этих моделей.

От наличия событий тут тоже мало что зависит, только что общая логика усложняется. И любой событийный интерфейс, и любой "инфраструктурный" интерфейс поддержки событий — это самые обыкновенные интерфейсы, и к ним применимы все те-же правила, что и к любым другим. А правило простое — любой интерфейс должен пердаваться в другой апартамент только через маршалинг.
Например, Вы похоже pIConnectionPoint передаёте без маршалинга, что уже является ошибкой.

Но вообще мне, честно говоря, не очень нравится Ваша схема. Я бы сразу при подписке маршалировал событийный интерфейс в GIT, а в потоке один раз их демаршалировал. Разумеется, это потребует реализации собственного механизма подписки — IConnectionPointContainer для этого не слишком удачный выбор, но оно того стоит, по-моему. Если конечно вообще оправдана генерация событий в отдельном потоке. Может лучше чтобы доп. поток извещал главный о завершении обработки, а тот уже генерировал бы события?

S>А могут быть проблемы от "кривости" клиента? Клиент написан на Borland C++ Builder.


Я билдера не знаю, но сильно сомневаюсь.
"Нормальные герои всегда идут в обход!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.