Читаем Сущность технологии СОМ. Библиотека программиста полностью

Атрибут [pointer_default] применяется только к тем вложенным указателям, семантика которых не квалифицирована явно. В приведенном выше определении интерфейса единственный указатель, к которому это относится, – это элемент данных pVal структуры FOO. Элемент pNode структуры NODE явно квалифицирован как уникальный указатель, поэтому установка [pointer_default] на него не влияет. На параметры метода pFoo и pHead атрибут [pointer_default] также не влияет, поскольку они являются указателями высшего уровня и по умолчанию [ref], если только они не квалифицированы явно иным образом (как в случае с pHead).

Основная причина, по которой вложенные указатели имеют в СОМ отдельный статус, заключается в том, что они предъявляют особые требования к организации памяти. Для параметров с атрибутом [in] различие между указателями высшего уровня и вложенными указателями не слишком существенно, так как вызывающая программа обеспечивает метод всеми значениями и поэтому должна заранее выделить память, которую эти значения будут занимать:

HUMAN bob = { 2231 };

DOG fido = { 12288, &bob };

// fido is owned by bob

// fido принадлежит bob'y

HRESULT hr = p->TakeToGroomer(&fido);

// this is correct!

// это правильно!

В то же время разграничение между указателями высшего уровня и вложенными является существенным, когда оно касается организации памяти для параметров [out] и [in,out]. Для обоих параметров, [out] и [in,out], память, на которую ссылаются указатели высшего уровня, управляется вызывающим оператором, как и в случае параметров [in]. Для вложенных же указателей, которые появляются в параметрах [out] и [in, out], память управляется вызываемым оператором (самим методом). Причина появления этого правила заключается в том, что глубина вложения типов данных может быть сколь угодно большой. Например, в таком определении типа:

typedef struct tagNODE {

short value;

[unique] struct tagNODE *pNext;

} NODE:

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

При наличии правила, по которому разработчики метода должны выделять память при инициализации любых вложенных указателей, возникает естественный вопрос, откуда методы должны получить эту память, чтобы вызывающие операторы знали, как освободить ее после прочтения всех возвращенных значений? Ответом является распределитель памяти (task allocator) СОМ-задачи. Распределителем памяти задачи СОМ называется распределитель памяти, индивидуальный для каждого процесса, используемый исключительно для выделения памяти вложенным указателям с атрибутами [out] и [in,out]. Проще всего использовать этот распределитель памяти СОМ-задачи посредством применения трех API-функций СОМ:

void *CoTaskMemAlloc(DWORD cb);

// allocate cb bytes

// размещаем cb байтов

void CoTaskMemFree(void *pv);

// deallocate memory at *pv

// освобождаем память в *pv

void *CoTaskMemRealloc(void *pv,DWORD cb);

// grow/shrink *pv

// расширяем/сжимаем *pv

Семантика этих трех функций такая же, как у их эквивалентов из динамической библиотеки С: malloc, free и realloc. Разница состоит в том, что они предназначены исключительно для выделения памяти параметрам типа вложенных указателей с атрибутами [out] и [in,out]. Другое важное отличие состоит в том, что подпрограммы из динамической библиотеки С нельзя использовать для выделения памяти в одном модуле и освобождения ее в другом. Дело в том, что детали реализации каждой динамической библиотеки С являются специфическими и изменяются при смене компилятора. Так как все участники согласились использовать один и тот же распределитель, предлагаемый СОМ, нет проблемы с освобождением клиентом памяти, которая выделена объектом, скомпилированным в отдельной DLL.

Чтобы понять, как используются на практике блоки памяти, выделенные вызываемым оператором, рассмотрим приводившийся ранее метод GetFromPound:

HRESULT GetFromPound([out] DOG *pDog);

В то время как память для объекта DOG должна быть выделена вызывающей программой (pDog является указателем высшего уровня), память для объекта HUMAN должна быть выделена реализацией метода с использованием распределителя памяти задачи (pDog->pOwner является вложенным в [out]-параметр указателем). Реализация метода выглядела бы примерно так:

STDMETHODIMP GetFromPound(/*[out]*/DOG *pDog)

{

short did = LookupNewDogId();

short hid = LookupHumanId(did);

pDog->nDogID = did;

// allocate memory for embedded pointer

// выделяем память для вложенного указателя

pDog->pOwner = (HUMAN*) CoTaskMemAlloc(sizeof(HUMAN));

if (pDog->pOwner == 0)

// not enough memory

// недостаточно памяти

return R_OUTOFMEMORY;

pDog->pOwner->nHumanID = hid;

return S_OK;

}

Отметим, что метод возвращает специальный HRESULT E_OUTOFMEMORY, указывающий на то, что операция прервана из-за нехватки памяти.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных