STDMETHODIMP Monitor::StartMonitoring(void) {
// ensure that stub manager/object stays alive
// убеждаемся, что администратор заглушек/объект остается жив
HRESULT hr = CoLockObjectExternal(this, TRUE, FALSE);
// start hardware monitoring
// начинаем контроль за аппаратным устройством
if (SUCCEEDED(hr))
hr = this->EnableHardwareProbe();
return hr; }
а также другой метод, который предписывает объекту закончить активный контроль:
STDMETHODIMP Monitor::StopMonitoring(void)
{
// stop hardware monitoring
// прекращаем контроль за устройством
this->DisableHardwareProbe();
// allow stub manager/object to die when no clients exist
// разрешаем администратору заглушек/объекту прекратить
// существование, когда нет клиентов
hr = CoLockObjectExternal(this, FALSE, TRUE);
return hr; }
Если принять, что объект был изначально маршалирован с помощью слабой таблицы маршалинга, то данный код обеспечивает жизнь администратора заглушек и объекта до тех пор, пока хотя бы один неосвобожденный заместитель или объект активно контролируют основное устройство.
Кроме предоставления разработчикам объектов возможности устанавливать счетчик внешних ссылок в администраторе заглушек, СОМ также позволяет разработчикам явно уничтожать администратор заглушек, независимо от числа неосвобожденных объектных ссылок. В СОМ предусмотрена API-функция CoDisconnectObject , которая находит администратор заглушек объекта и уничтожает его, отсоединяя все существующие в данный момент заместители:
HRESULT CoDisconnectObject(
[in] Unknown * pUnkObject,
// ptr to object
// указатель на объект
[in] DWORD dwReserved
// reserved, must be zero
// зарезервировано, должно равняться нулю
);
Подобно CoLockObjectExternal , функция CoDisconnectObject должна вызываться из процесса действующего объекта и не может быть вызвана на объект. Для того чтобы применить CoDisconnectObject к показанному выше объекту контроля за устройством, рассмотрим, что произошло бы, если бы состояние объекта было испорчено. Для предотвращения дополнительных вызовов методов объекта, которые могут возвращать ошибочные результаты, объект мог бы вызвать CoDisconnectObject , чтобы резко отсоединить все существующие заместители:
STDMETHODIMP Monitor::GetSample(/*[out]*/ SAMPLEDATA *ps) {
HRESULT hr = this->GetSampleFromProbe(ps);
if (FAILED(hr))
// probe or object may be corrupted
// образец или объект могут быть испорчены
CoDisconnectObject(this, 0);
return hr; }
Функция CoDisconnectObject используется также в случаях, когда процесс хочет отключиться, хотя один или более его объектов могут иметь неосвобожденные заместители. При явном вызове CoDisconnectObject до уничтожения любых объектов, которые могут иметь оставшиеся заместители, нет риска, что исходящие ORPC-запросы будут обслуживаться после того, как объект уже уничтожен. Если бы входящий ORPC-запрос должен был бы поступить после того, как объект уже уничтожен, но администратор заглушек еще жив, то небрежность привела бы к вызову интерфейсной заглушкой соответствующего метода из участка памяти, ранее известного как данный объект. Это вызвало бы лишние неприятности, связанные с тщетными усилиями по отладке.
Обе функции – CoLockObjectExternal и CoDisconnectObject – могут быть использованы разработчиком объектов для манипулирования администратором заглушек. Часто бывает полезно знать, есть ли в администраторе заглушек в наличии какие-либо заместители или объектные ссылки, маршалированные по сильной таблице ( strong marshals ). Для информирования объектов о том, что имеются неосвобожденные внешние ссылки на администратор заглушек, в СОМ определен интерфейс IExternalConnection , который может быть экспортирован объектами:
[ uuid(00000019-0000-0000-C000-000000000046), object, local ]
interface IExternalConnection : IUnknown {
DWORD AddConnection(
[in] DWORD extconn,
// type of reference
// тип ссылки
[in] DWORD reserved
// reserved, must be zero
// зарезервировано, должно быть равно нулю
);
DWORD ReleaseConnection(
[in] DWORD extconn,
// type of reference
// тип ссылки
[in] DWORD reserved,
// reserved, must be zero
// зарезервировано, должно быть равно нулю
[in] BOOL fLastReleaseCloses
// should kill stub?
// нужно ли убить заглушку?
); }
При первом подсоединении администратора заглушек к объекту он спрашивает объект, желает ли тот, чтобы его уведомляли о создании или уничтожении внешних ссылок. Он делает это посредством запроса интерфейса IExternalConnection для QueryInterface . Если объект не реализует IExternalConnection , то администратор заглушек будет использовать свой собственный счетчик ссылок при решении вопроса, когда уничтожать администратор заглушек. Если же объект предпочтет реализовать IExternalConnection , то в этом случае администратор заглушек будет жить до тех пор, пока объект явно не уничтожит его путем вызова CoDisconnectObject .
Читать дальше