Какие классы интеллектуального указателя COM использовать?

Меня смущает выбор классов интеллектуальных указателей COM для программирования на С++:

Там три четыре, о которых я знаю:

  • CCOMPtr от ATL
  • _com_ptr_t из классов поддержки MS Com
  • TComInterface (потому что я использую С++ Builder 2009)
  • CCOMQIPtr, (который я ранее забыл)

Я читал о различиях в обработке ошибок и исключений из первых двух, но TComInterface кажется полностью недокументированным. Как первые два, кажется, имеют gotchas или "неожиданное" поведение, из того, что я могу найти.

В идеале, мне бы хотелось что-то, что чистым и современным С++, но boost::com не существует, насколько я знаю...

Мне нужно управлять приложением от другого поставщика. Они предоставляют COM-интерфейс через файл TLB.

Ответ 1

Если вы используете материал импорта библиотеки типов, он будет генерировать код на основе _com_ptr_t и связанных классов поддержки COM. Идем дальше и используем их, если вы просто используете материал из этих библиотек.

Если вы пишете код на основе ATL, используйте CCOMPtr и другие классы на основе ATL.

Вещи могут стать уродливыми, если вам нужно смешивать и сопоставлять оба типа, но вы, вероятно, должны просто устроиться с ними и использовать то, что имеет наибольший смысл для того, что вы делаете в то время.

Хорошо, что у вас есть источник всех этих вещей, поэтому вам не нужно полагаться только на документацию (которая не проявляла особой осторожности, так как появился .NET).

Ответ 2

Поскольку вы просите "чистый и современный" стиль С++ и даете импульс в качестве примера, я добавлю еще два: std/boost::shared_ptr и boost::intrusive_ptr. По-видимому, intrusive_ptr является более естественным выбором, поскольку объекты COM имеют встроенный механизм подсчета ссылок. shared_ptr работает так же хорошо, вам нужно использовать только пользовательский удаляющий вызов, который вызывает IUnknown::Release(), и небольшую функцию генератора объектов, которая выполняет IUnknown::AddRef() и возвращает интеллектуальный указатель.

Я обычно иду с intrusive_ptr, поэтому я объясню это более подробно. Во-первых, конечно, intrusive_ptr_add_ref и intrusive_ptr_release должны быть реализованы для всех IUnknown s. Конструктор intrusive_ptr уже имеет удобную функцию, чтобы пропустить добавление другой ссылки, поскольку многие функции COM будут делать AddRef() для вас.

Теперь есть одна проблема с этим подходом: intrusive_ptr не раскрывает свой основной указатель, как некоторые из других указателей COM. Это проблема, поскольку обычный способ создания COM-объектов заключается в передаче указателя на указатель на некоторую функцию создания в другом объекте. Поскольку вы не можете передать intrusive_ptr в эти функции, вы получаете неуклюжие временные указатели, которые используются для инициализации intrusive_ptr. Это не очень элегантно, не говоря уже об исключительной безопасности (если вам это нужно вообще с COM-кодом, который, естественно, не бросает исключения. Я переводит COM-ошибки в исключения, хотя.)

Итак, я здесь использую другую функцию инструмента, которая превращает функцию, которая принимает любую ком-функцию, и возвращает вызываемый, где любой параметр, являющийся указателем-на-указатель-to-T, может быть либо ссылкой, либо ссылкой на intrusive_ptr. Все остальное похоже на "функцию ввода". Затем эти функции выполняют все преобразования между T ** и intrusive_ptr & для меня. Например, HRESULT CreateBuffer(IBuffer** bufferOut, int size) становится вызываемым с сигнатурой HRESULT CreateBuffer(instrusive_ptr<IBuffer>& bufferOut, int size). Они немного утомительны, чтобы писать для "всех" артефактов, если у вас нет генератора кода, большого терпения или, я полагаю, вариативных шаблонов. Но как только вы их получите, это действительно делает работу с COM очень приятной.

Ответ 3

Я использовал первые два, CComPtr и _com_ptr_t.

Похоже, вы уже прочитали о различиях с ошибками и обработкой исключений, поэтому выберите тот, который вам больше всего понравился, или который наиболее точно соответствует остальной части обработки ошибок в вашем коде.

Ответ 4

В качестве kenny вы можете использовать CComPtr для управления указателями на COM-интерфейсы. Этот класс хорошо документирован (см. msdn) и использует автоматический подсчет ссылок, что, я полагаю, вы хотите.

Вопрос OTOH, Rob важен: действительно ли вы используете COM-интерфейсы? Для простых указателей вы можете использовать интеллектуальные указатели из библиотек STL или boost, которые в любом случае лучше (в общем), чем CComPtr.