В данной главе рассматривались вопросы, относящиеся к выделению классов в отдельные серверные процессы. COM поддерживает запуск серверных процессов на основе запросов на активацию. Эти серверные процессы должны саморегистрироваться с помощью библиотеки COM, используя
Разное
IChapter *pc = 0;
HRESULT hr = CoGetObject(OLESTR(«Chapter:7»), О,
IID_IChapter, (void**)&pc);
if (SUCCEEDED(hr)) {
hr = pc->IncludeAllTopicsNotCoveredYet();
pc->Release(); }
В предыдущей главе были представлены основы модели программирования СОМ и архитектуры удаленного доступа. Различные интерфейсы и методики СОМ рассматриваются на протяжении всей книги. Однако осталось несколько вопросов, не связанных ни с какой определенной главой, о которых следует рассказать подробно. Вместо того чтобы просто втиснуть эти вопросы в другие главы, которые были скомпонованы рационально или даже превышали разумные размеры, я отвел данную главу под хранилище для «маленьких» тем, которые не всегда подходят к другим частям книги. За исключением вводных разделов об указателях, управлении памятью и массивах, ни одна из этих тем не является жизненно необходимой для создания эффективных распределенных систем с СОМ. Помните об этом и расслабьтесь, в то время как ваши глаза будут скользить вдоль строк этой главы.
Основы указателей
СОМ, подобно DCE (Distributed Computing Environment – среда распределенных вычислений), ведет свое начало от языка программирования С. Хотя лишь немногие разработчики используют С для создания или использования компонентов СОМ, именно от С СОМ унаследовала синтаксис для своего языка определений интерфейсов (Interface Definition Language – IDL). Одной из наиболее сложных проблем при разработке и использовании интерфейсов является управление указателями. Рассмотрим такое простое определение метода IDL:
HRESULT f([in] const short *ps);
Если бы вызывающая программа должна была запустить этот метод так:
short s = 10;
HRESULT hr = p->f(&s);
то величину 10 следовало бы послать объекту. Если бы этому методу нужно было выйти за границы апартамента, то интерфейсный заместитель был бы обязан разыменовать указатель и передать величину 10 в сообщение ORPC-запроса.
Следующий клиентский код, хотя и написан целиком в традициях С, представляет собой более интересный случай:
HRESULT hr = p->f(0);
// pass a null pointer
// передаем нулевой указатель
Если вызывающий поток выполняется в апартаменте объекта, то заместителя нет и нулевой указатель будет передан прямо объекту. Но что если объект расположен в другом апартаменте и заместитель используется? Что в точности должен передать интерфейсный заместитель, чтобы показать, что был послан нулевой указатель? Кроме того, означает ли это, что интерфейсные заместители и заглушки должны проверять каждый указатель, не является ли он нулевым? Оказывается, бывают ситуации, в которых указатель никогда не должен быть нулевым, и другие ситуации, когда нулевые указатели, наоборот, чрезвычайно полезны как начальные значения. В последнем случае факт передачи нулевого указателя интерфейсному заместителю должен быть продублирован интерфейсной заглушкой в апартаменте объекта.
Для того чтобы удовлетворить этим столь различным требованиям, СОМ позволяет разработчикам интерфейсов указывать точную семантику каждого параметра указателя. Чтобы показать, что указатель никогда не должен принимать нулевого значения, разработчик интерфейса может применить атрибут [ref]:
HRESULT g([in, ref] short *ps);
// ps cannot be a null ptr.
// ps не может быть нулевым указателем
Указатели, использующие атрибут [ref], называются ссылочными указателями (reference pointers). При IDL-определении, приведенном выше, следующий код со стороны клиента:
HRESULT hr = p->g(0);
// danger: passing null [ref] ptr.
// опасность: передается нулевой указатель с атрибутом [ref]
является ошибочным. И если p указывает на интерфейсный заместитель, то данный интерфейсный заместитель обнаружит нулевой указатель и возвратит вызывающей программе ошибку маршалинга, даже не передав метод текущему объекту. А чтобы сделать нулевой указатель допустимым значением параметра, в IDL-определении следует использовать атрибут [unique]:
HRESULT h([in, unique] short *ps);