2016-11-19 7 views
0

Когда вы регистрируете COM-объект в таблице рабочих столов с нулевым флагом (с запросом на слабый ref), ROT увеличивает счетчик ссылок на 1. Акт получения объекта из ROT увеличивает счетчик ссылок еще на один. После освобождения этого объекта объект остается живым с количеством ссылок, по крайней мере, одного. Его регистрация в ROT также не отменяется магией после извлечения.Как работает таблица текущих объектов для реализации слабых ссылок?

Как это слабо? Как это отличается от сильной регистрации?

Прочная регистрация соответствует такому же шаблону - как регистрация, так и поиск увеличивают количество ссылок на единицу.

Указатель интерфейса, который ROT возвращает к внутренним клиентам, не является прокси; ROT не знает, что я освободил свой восстановленный указатель интерфейса.

+0

Из [IRunningObjectTable :: Register] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680747.aspx): * " Для слабой регистрации (ROTFLAGS_REGISTRATIONKEEPSALIVE не установлен) ROT будет освобождать объект всякий раз, когда выдается последняя сильная ссылка на объект. Для сильной регистрации (набор ROTFLAGS_REGISTRATIONKEEPSALIVE) ROT предотвращает уничтожение объекта до тех пор, пока регистрация объекта не будет явно отозван. "* – IInspectable

+0

Я читал это. Не могли бы вы объяснить, что означает «последняя сильная ссылка на объект, выпущенный»? Если вы просто получите его из ROT и затем отпустите, он не освободит объект. В слабом сценарии ROT содержит ссылку, как в сильной. –

+0

То, как я это понимаю (и я должен признать, что я никогда не делал дополнительной проверки), заключается в том, что запрос сильной регистрации «ROTFLAGS_REGISTRATIONKEEPSALIVE» гарантирует, что ROT имеет действительную ссылку независимо от того, что. Без флага он запускается аналогичным образом (просто нет другого способа, например, эта документация утверждает, что начальный «AddRef» всегда происходит), но API оставляет за собой право выпускать запись в любое время, особенно. на конкретном событии, таком как выпуск прокси. –

ответ

1

действительно удаление от поведения ROT зависит не только от ROTFLAGS_REGISTRATIONKEEPSALIVE флага, но также (и как) ваш объект реализован IExternalConnection

(специального примечания для @IInspectable только - да все это без документов, без поддержки, может изменился - поэтому, пожалуйста, не читайте больше).

когда мы регистрируем объект в ROT com, всегда запрашиваем его для интерфейса IExternalConnection. если объект не реализован, используется стандартная реализация.

в случаеROTFLAGS_REGISTRATIONKEEPSALIVE уже во время регистрации IExternalConnection::AddConnection. поэтому у нас уже есть 1 внешнее соединение. без ROTFLAGS_REGISTRATIONKEEPSALIVE - этот метод не называется.

каждый раз, когда кто-то называют IRunningObjectTable::GetObject (! От другой квартиры) в CRemoteUnknown::RemAddRef называется в нашем процессе. этот метод позвоните по номеру IExternalConnection::AddConnectionтолько если зарегистрируйтесь безROTFLAGS_REGISTRATIONKEEPSALIVE флаг.

каждый раз, когда мы окончательный Release объект (по доверенности, полученной от предыдущего GetObject вызова!) - CRemoteUnknown::RemReleaseWorker называется в нашем местном процессе. и он внутренне звонит IExternalConnection::ReleaseConnectionтолько в случае noROTFLAGS_REGISTRATIONKEEPSALIVE на объекте. стандартная реализация IExternalConnection по номеру CStdMarshal::Disconnect ->InternalIrotRevoke, когда внешняя ссылка (не общая ссылка объекта) достигает 0 и fLastReleaseCloses == TRUE - в результате наш объект отменяется с ROT. но если мы выполним IExternalConnection самостоятельно, мы можем позвонить или не позвонить CoDisconnectObject, чтобы мы могли быть отозваны или нет из ROT.

и, наконец, когда мы прямо или косвенно вызов IRunningObjectTable::Revoke ком вызов IExternalConnection::ReleaseConnectionесли мы регистрируем сROTFLAGS_REGISTRATIONKEEPSALIVE.

так вывод:

если мы фиксируем с ROTFLAGS_REGISTRATIONKEEPSALIVE - IExternalConnection::AddConnection будет вызываться только один раз во время регистрации (. На самом деле можно назвать сказать n+1 время и n время - ReleaseConnection - но все это внутри IRunningObjectTable::Register вызова) , когда кто-то получит наш объект от ROT - мы будем не уведомлены об этом. и, наконец, IExternalConnection::ReleaseConnection будет называться также только один раз, когда мы позвоним IRunningObjectTable::Revoke.

с другой стороны, если мы не используем ROTFLAGS_REGISTRATIONKEEPSALIVE флаг - IExternalConnection методы будут не называется на Register и Revoke. но это будет несколько раз по имени на IRunningObjectTable::GetObject и окончательный Release (на объекте прокси). если мы не реализовали IExternalConnection самостоятельно или позвонили по номеру CoDisconnectObject, когда внешние ссылки достигли 0 и fLastReleaseCloses - мы будем удалены из ROT. но мы освобождаем не звонимCoDisconnectObject (в этом случае поведение будет таким, как мы используем ROTFLAGS_REGISTRATIONKEEPSALIVE) или произнесите его при некотором условии.

Преимущество - мы можем отслеживать использование каждого нашего объекта в случае, если флажок и ROTFLAGS_REGISTRATIONKEEPSALIVE флаг и решить сами по себе, необходимо отключить, если внешние ссылки достигнут 0 или нет.

и последний - если мы позвоним IRunningObjectTable::GetObject из той же квартиры, где мы позвоним IRunningObjectTable::Register - мы получили не прокси, а указатель прямого объекта. в этом случае, конечно, не будет вызовов IExternalConnection методов

+0

Теперь это имеет смысл. Я протестировал сценарий с нестандартным клиентом, когда он отключается, объект освобождается полностью до нуля. –

+0

@SevaAlekseyev - да, принципиально разные здесь между нестандартным клиентом (действительно прокси) и квартирами. однако для лучшего понимания ситуации - хорошо реализовать «IExternalConnection» на самообъекте (всего 2 простых метода) и будет очень понятным после этого – RbMm