Ответ 1
Это не ответ, как набор проблем, почему это очень сложно сделать - я помещаю его в качестве ответа, поскольку здесь слишком много информации, чем подходит в комментарии:)
Я понимаю, что понятие слабой ссылки просто не существует в COM-периоде. У вас есть подсчет ссылок через IUnknown и что общая сумма того, как COM имеет дело с управлением жизненным циклом объекта. Все, кроме этого, строго говоря, не COM.
(Net поддерживает концепцию, но у нее есть фактический менеджер памяти на основе GC для обеспечения соответствующей поддержки и может обрабатывать объекты WeakRef по-другому, чем обычные ссылки в памяти. Но это не так с очень простым миром, что COM предполагает, что это мир простой памяти и указателей, и немного больше.)
COM указывает, что подсчет ссылок для каждого интерфейса; любой COM-объект может свободно выполнять подсчет ссылок на объект в качестве удобства, но результатом является то, что если вы обертываете объект, вы должны принять наиболее ограничительный случай. Поэтому вы не можете предположить, что любой данный IUnknown будет использоваться для всех addrefs/release на этом объекте: вам действительно нужно будет отслеживать каждый интерфейс отдельно.
Канонический IUnknown - тот, который вы возвращаете QI'ing для IUnknown - может быть любым интерфейсом вообще - даже выделенный IUnknown, который используется только для того, чтобы действовать как личность! - до тех пор, пока одно и то же значение двоичного указателя возвращается каждый раз. Все остальные интерфейсы могут быть реализованы любым способом; обычно одно и то же значение возвращается каждый раз, но COM-объект может законно возвращать новый IFoo каждый раз, когда кто-то QI для IFoo. Или даже держите кеш в IFoos и возвращайте случайным образом.
... и тогда у вас есть агрегация, с которой нужно иметь дело - в принципе, у COM нет четкой концепции объекта вообще, все о интерфейсах. Объекты в COM - это всего лишь набор интерфейсов, которые используют один и тот же канонический IUnknown: они могут быть реализованы как один объект C/С++ за кулисами или как семейство связанных объектов C/С++, представляющих собой фасад "один COM-объект".
Сказав все это, учитывая, что:
Я отслеживаю состояние различных компонентов (включая все COM-объекты) этого программного обеспечения ради отладки
Здесь альтернативный подход, который может дать некоторые полезные данные для отладки с помощью.
Идея здесь заключается в том, что многие реализации COM-объектов возвращают значение ref в качестве возвращаемого значения Release() - поэтому, если они возвращают 0, то это означает, что интерфейс, возможно, был выпущен.
Однако это не гарантируется: MSDN:
Метод возвращает новый счетчик ссылок. Это значение предназначено для использования только в целях тестирования.
(выделено мной)
Но это, по-видимому, то, что вы здесь делаете.
Итак, одна вещь, которую вы могли бы сделать, предполагая, что у вас есть код вызова, заключается в замене вызовов с помощью Release() с помощью строки MyRelease() или аналогичной, которая будет вызывать выпуск, и если она замечает, что возвращаемое значение равно 0, затем замечает, что теперь указатель интерфейса освобожден - удаляет его из таблицы, записывает в файл и т.д.
Одно важное предостережение: имейте в виду, что у COM нет понятия слабого ref, даже если вы пытаетесь что-то взломать. Использование указателя COM-интерфейса, который не был AddRef() 'd, является незаконным в отношении COM; поэтому, если вы сберете значения указателя интерфейса в любом списке, единственное, что вы должны сделать с ними, - рассматривать их как непрозрачные числа для целей отладки (например, записывать их в файл, чтобы вы могли коррелировать создание с помощью деструкций или отслеживать сколько у вас выдающихся), но не пытайтесь использовать их в качестве фактических указателей интерфейса.
Опять же, имейте в виду, что ничто не требует, чтобы объект COM выполнял соглашение о возврате refcount; поэтому имейте в виду, что вы можете видеть что-то похожее на ошибку, но на самом деле просто реализация Release просто происходит, всегда возвращается 0 (или rand(), если вам особенно не повезло!)