- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
Шрифт:
Интервал:
Закладка:
STDMETHODIMP MyClass::j(short *ps1, short *ps2)
{
if (ps1 == ps2)
return this->OneKindOfBehavior(ps1);
else
return this->AnotherKindOfBehavior(ps1, ps2);
}
то интерфейсный маршалер нарушил бы семантический контракт (semantic contract) интерфейса, что нарушило бы прозрачность экспорта в СОМ.
Наличие атрибутов указателя [ref] и [unique] означает, что память, на которую ссылается указатель, не является ссылкой для какого-либо другого указателя в вызове метода и что интерфейсный маршалер не должен осуществлять проверку на дублирование указателей. Для того чтобы показать, что указатель может ссылаться на память, на которую ссылается другой указатель, разработчику IDL следует использовать атрибут [ptr]:
HRESULT k([in, ptr] short *ps1, [in, ptr] short *ps2);
Указатели, использующие атрибут [ptr], называются полными указателями (full pointers), потому что они наиболее близки к полному соответствию с семантикой языка программирования С. Имея такое IDL-определение, следующий код со стороны клиента:
short x = 100;
HRESULT hr = p->k(&x, &x);
// note: same ptr. passed twice
// заметим: тот же самый указатель передан дважды
передаст значение 100 ровно один раз, поскольку атрибут [ptr] при параметре ps1 сообщает интерфейсному маршалеру, что следует выполнить проверку на дублирование для всех остальных указателей с атрибутом [ptr]. Поскольку параметр ps2 также использует атрибут [ptr], интерфейсный маршалер определит значение дублирующего указателя[2], а разыменует и передает значение только одного из указателей. Интерфейсная заглушка отметит, что это значение должно быть передано с обоими параметрами, ps1 и ps2, вследствие чего метод получит один и тот же указатель в обоих параметрах.
Хотя полные указатели могут решать различные проблемы и в определенных случаях полезны, они не являются предпочтительными указателями в семантике СОМ. Дело в том, что в большинстве случаев разработчик знает заранее, что дублирующие указатели передаваться не будут. Кроме того, поскольку полные указатели обеспечивают более короткие ORPC-сообщения в случае, если они являются дублирующими указателями, то расход ресурсов процессора на поиск дублирующих указателей может стать нетривиальным с ростом числа указателей на каждый метод. Если разработчик интерфейса уверен, что никакого дублирования не будет, то разумнее учесть это и использовать либо уникальные, либо ссылочные указатели.
Указатели и память
Интерфейсы, показанные в данной главе до настоящего момента, были довольно просты и использовали только примитивные типы данных. При применении сложных типов данных одной из наиболее серьезных проблем является управление памятью для параметров метода. Рассмотрим следующий прототип функции IDL:
HRESULT f([out] short *ps);
При наличии такого прототипа нижеследующий код вполне допустим с точки зрения С:
short s;
HRESULT hr = p->f(&s);
// s now contains whatever f wrote
// s теперь содержит все, что написал f
Должно быть очевидно, как организована память для такой простой функции. Однако часто начинающие (и не только начинающие) программисты по ошибке пишут код, подобный следующему:
short *ps;
// the function says it takes a short *, so ...
// функция говорит, что она берет * типа short, следовательно ...
HRESULT hr = p->f(ps);
При рассмотрении следующей допустимой реализации функции:
STDMETHODIMP MyClass::f(short *ps)
{
static short n = 0;
*ps = n++;
return S_OK;
}
очевидно, что выделение памяти для короткого целого числа и передача ссылки на память в качестве аргумента функции является обязанностью вызывающей программы. О только что приведенной реализации заметим, что для функции неважно, откуда взялась эта память (например, динамически выделена из «кучи», объявлена как переменная auto в стеке), до тех пор, пока текущий аргумент ссылается на допустимую область памяти. Для подкрепления этого положения СОМ требует, чтобы все параметры с атрибутами [out], являющиеся указателями, были ссылочными указателями.
Ситуация становится менее очевидной, когда вместо простых целых типов используются типы, определенные пользователем. Рассмотрим следующее IDL-определение:
typedef struct tagPoint {
short x;
short у;
} Point;
HRESULT g([out] Point *pPoint);
Как и в предыдущем примере, правильной является такая схема: вызывающая программа выделяет память для значений и передает ссылку на память, выделенную вызывающей программой:
Point pt;
HRESULT hr = p->g(&pt);
Если вызывающая программа передала неверный указатель:
Point *ppt;
// random unitialized pointer
// случайный неинициализированный указатель
HRESULT hr = p->g(ppt);
// where should proxy copy x & у to?
// куда заместитель должен копировать x и у ?
то не найдется легальной памяти, куда метод (или интерфейсный заместитель) мог бы записать значения x и y.
Чем более сложные типы определяются пользователем, тем интереснее становится сценарий. Рассмотрим следующий код IDL:
[uuid(E02E5345-l473-11d1-8C85-0080C73925BA),object ]
interface IDogManager : IUnknown {
typedef struct tagHUMAN {
long nHumanID;
} HUMAN;
typedef struct tagDOG {
long nDogID;
[unique] HUMAN *pOwner;
} DOG;
HRESULT GetFromPound([out] DOG *pDog);
HRESULT TakeToGroomer([in] const DOG *pDog);
HRESULT SendToVet([in, out] DOG *pDog);
}
Отличительная особенность этого интерфейса состоит в том, что теперь вызывающая программа должна передать указатель на такой участок памяти, который уже содержит указатель. Можно показать, что для приведенного выше определения метода следующий код является правильным:
DOG fido;
// argument is a DOG *, so caller needs a DOG
// аргументом является DOG *, поэтому вызывающей программе нужен DOG
HUMAN dummy;
// the DOG refers to an owner, so alloc space?
// DOG ссылается на владельца, поэтому выделяем память?
fido.pOwner = &dummy;
HRESULT hr = p->GetFromPound(&fido);
// is this correct?
// правильно ли это?
В данном коде предполагается, что вызывающая программа ответственна за выделение памяти для DOG, который передается по ссылке. В этом смысле код правилен. Однако в этом коде также предполагается, что он отвечает за управление любой памятью более низкого уровня, на которую могут сослаться обновленные значения объекта DOG. Именно здесь данный код отступает от правил СОМ.
СОМ разделяет указатели, участвующие в вызове метода, на две категории. Любые именованные параметры метода, являющиеся указателями, относятся к указателям высшего уровня (top-level). Любой подчиненный указатель, который получен путем разыменования указателя высшего уровня, является вложенным (embedded) указателем. В методе GetFromPound параметр pDog считается указателем высшего уровня. Подчиненный указатель pDog->pOwner рассматривается как вложенный указатель. Отметим, что определение структуры DOG использует атрибут [unique] для явной квалификации семантики указателя для элемента структуры pOwner. Если бы семантика указателя не была квалифицирована явно, разработчик интерфейса мог бы применить принятый по умолчанию во всех интерфейсах для всех вложенных указателей атрибут [pointer_default]:
[ uuid(E02E5345-1473-11d1-8C85-0080C73925BA), object,
pointer_default(ref)
// default embedded ptrs to [ref]
// по умолчанию вложенные указатели [ref]
]
interface IUseStructs : IUnknown {
typedef struct tagNODE {
long val;
[unique] struct tagNODE *pNode;
// explicitly [unique]
// явно [unique]
} NODE;
typedef struct tagFOO {
long val;
long *pVal;
// implicitly [ref]
// неявно [ref]
} FOO;
HRESULT Method([in] FOO *pFoo, [in, unique] NODE *pHead);
}
Атрибут [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], память управляется вызываемым оператором (самим методом). Причина появления этого правила заключается в том, что глубина вложения типов данных может быть сколь угодно большой. Например, в таком определении типа: