Как Running Object Table реализует слабые ссылки?

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

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

Строгая регистрация происходит по одной схеме - и регистрация, и получение увеличивают количество ссылок на единицу.

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

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 только в случае, если нет ROTFLAGS_REGISTRATIONKEEPSALIVE на объекте. реализация по умолчанию IExternalConnection называется CStdMarshal::Disconnect -> InternalIrotRevoke когда внешняя ссылка (не общая ссылка на объект) достигает 0 и fLastReleaseCloses == TRUE - в результате наш объект отозван из ROT. но если мы реализуем IExternalConnection самостоятельно мы можем звонить или не звонить CoDisconnectObject так что мы можем быть отозваны или нет от ROT.

и, наконец, когда мы прямой или косвенный вызов IRunningObjectTable::Revoke Com Call 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 методы

Другие вопросы по тегам