Поделиться через


Implementing an STL-Based Collection

Библиотеки ATL предоставляет интерфейс ICollectionOnSTLImpl позволяет быстро реализовывать стандартной библиотеки шаблонов (STL) - интерфейсов коллекции, основанные на объектах. Чтобы понять, как работает этот класс будет работать через простой пример (см. ниже), используют этот класс для реализации доступную только для чтения коллекцию направили для клиентов автоматизации.

В образце кода из Образец ATLCollections.

Для выполнения этой процедуры необходимо:

  • Создайте новый простой объект.

  • Правка файл IDL для созданного интерфейса.

  • Создание 5 typedef, описывающие, как элементы коллекции хранятся и как они будут предоставлены клиентам через модель COM взаимодействует.

  • Создание 2 typedef для классов политики копирования.

  • создайте typedef для реализаций перечислителя и коллекции.

  • Правка мастер- созданный код C++ для использования typedef коллекции.

  • Добавьте код для заполнения коллекции.

Создание новый простой объект

Создайте новый проект, предоставляя, что очищено окно " атрибуты в окне параметры приложения. Использование библиотеки ATL диалоговое окно " добавление класса объекта и добавьте простой мастер для создания простого вызываемый объект Words. Убедитесь, что сдвоенный интерфейс IWords сформирован. Объекты созданного класса будут использоваться для представления коллекции слов (строк).

Изменение файла IDL

Теперь открыть idl-файл и добавьте значение 3 свойства необходимого, что повернул IWords в интерфейс коллекции, доступной только для чтения, как показано ниже:

[
   object,
   uuid(7B3AC376-509F-4068-87BA-03B73ADC359B),
   dual,                                                    // (1)
   nonextensible,                                           // (2)
   pointer_default(unique)
]
interface IWords : IDispatch
{
   [id(DISPID_NEWENUM), propget]                            // (3)
   HRESULT _NewEnum([out, retval] IUnknown** ppUnk);

   [id(DISPID_VALUE), propget]                              // (4)
   HRESULT Item([in] long Index, [out, retval] BSTR* pVal); // (5)

   [id(0x00000001), propget]                                // (6)
   HRESULT Count([out, retval] long* pVal);

};

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

  1. Интерфейсы коллекции обычно двойны поскольку клиенты автоматизации, получат доступ к свойству _NewEnum через IDispatch::Invoke. Однако клиенты автоматизации могут получить доступ к остальные методы в таблице vtable, поэтому сдвоенные интерфейсы предпочтительны для диспетчерских интерфейсов.

  2. Если сдвоенный интерфейс или диспетчерский интерфейс не будут расширены во время выполнения (то есть не обеспечите дополнительные методы или свойства в IDispatch::Invoke), необходимо применить атрибут nonextensible к определению. Этот атрибут позволяет клиентам автоматизации для выполнения полной проверки кода во время компиляции. В этом случае интерфейс не должен быть расширен.

  3. Правильный идентификатор DISPID важно, если необходимо, чтобы клиенты автоматизации использовать это свойство. (Обратите внимание, что только один символ подчеркивания в DISPID_NEWENUM).

  4. Можно ввести любое значение в виде DISPID свойства item. Однако item обычно использует DISPID_VALUE, чтобы сделать его свойство коллекции по умолчанию. Это позволяет клиентам автоматизации для обращения к свойству без именование его явно.

  5. Тип данных, используемый для возвращаемого значения свойства item тип элемента, хранящегося в коллекции, сколько клиентов модели COM. Интерфейс возвращает строки, поэтому необходимо использовать стандартный тип string в модели COM, BSTR. Можно сохранить данные в другом формате автоматически по мере того, как вы увидите скоро истекает.

  6. Значение, используемое для свойства Счетчик DISPID полностью произвольно. Нет стандартных DISPID для данного свойства.

Создание typedef для хранения и извлечения

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

Ответы на эти вопросы можно указать в форме нескольких typedef, которые можно добавить в верхней части файла заголовка для созданного класса:

// Store the data in a vector of std::strings
typedef std::vector< std::string >         ContainerType;

// The collection interface exposes the data as BSTRs
typedef BSTR                               CollectionExposedType;
typedef IWords                             CollectionInterface;

// Use IEnumVARIANT as the enumerator for VB compatibility
typedef VARIANT                            EnumeratorExposedType;
typedef IEnumVARIANT                       EnumeratorInterface;

В этом случае будут храниться данные как std::vectorstd::string. std::vector класс контейнеров STL, который ведет себя как управляемый массив. std::string класс строки стандартной библиотеки C++. Эти классы упрощают работу с коллекцией строк.

Поскольку поддержка Visual Basic существена к успешности выполнения этого интерфейса перечислителя, возвращенный свойством _NewEnum должен поддерживать интерфейс IEnumVARIANT. Это единственный интерфейс перечислителя, воспринимаемый Visual Basic.

Создание typedef для классов политики копирования

Typedef, созданного до тех пор, предоставляющие все необходимые сведения для создания более дополнительных typedef для классов копии, которые используются перечислителем и коллекцией.

// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;

В этом примере можно использовать заданный класс GenericCopy VCUE_Copy.h и VCUE_CopyString.h из пользовательских в образце ATLCollections. Этот класс можно использовать в коде, но можно определить дальнейшие специализации GenericCopy для поддержки типов данных, используемых в пользовательских коллекциях. Дополнительные сведения см. в разделе Классов политики копирования библиотеки ATL.

Создание typedef для перечисления и коллекции

Теперь все параметры шаблона, необходимые для специализировала классы CComEnumOnSTL и ICollectionOnSTLImpl для этой ситуации были представлены в форме typedef. Чтобы упростить использование специализаций создайте 2 больше typedef как показано ниже:

typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;

Теперь CollectionType синоним для специализации ICollectionOnSTLImpl, которая реализует интерфейс IWords заданный ранее, и предоставляет перечислитель, который IEnumVARIANT поддержки.

Изменение Мастер- Созданный код

Теперь необходимо создать CWords от реализации интерфейса, представленной typedef CollectionType, а не IWords, как показано ниже:

class ATL_NO_VTABLE CWords :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CWords, &CLSID_Words>,
   // 'CollectionType' replaces 'IWords' in next line
   public IDispatchImpl<CollectionType, &IID_IWords, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORDS)


BEGIN_COM_MAP(CWords)
   COM_INTERFACE_ENTRY(IWords)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// Remainder of class declaration omitted.

Добавление кода для заполнения коллекции

Единственная всего, которая остается заполнения вектор с данными. В этом простом примере можно добавить несколько слов в коллекции в конструкторе для данного класса:

CWords()
{
    m_coll.push_back("this");
    m_coll.push_back("is");
    m_coll.push_back("a");
    m_coll.push_back("test");
}

Теперь можно проверить код с клиентом.

См. также

Основные понятия

Коллекции и перечислители ATL

Образец ATLCollections

ATL Copy Policy Classes