Как 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
методы