Литмир - Электронная Библиотека
A
A

if (pcFetched == 0 && cElems != 1) return E_INVALIDARG;

// provide a location for last [out] param

// обеспечиваем место для последнего [out]-параметра

ULONG cFetched;

if (pcFetched == 0) pcFetched = &cFetched;

// call remote method with non-null pointer as last param

// вызываем удаленный метод с ненулевым указателем

// в качестве последнего параметра

return IEnumDouble_RemoteNext_Proxy(This, cElems, prg, pcFetched);

}

Отметим, что во всех случаях отправляемая версия метода получает в качестве последнего параметра ненулевой указатель.

Определяемая пользователем подпрограмма [local]-to-[call_as] будет вызываться интерфейсной заглушкой после демаршалинга отправляемой формы метода. Эта подпрограмма предназначена для преобразования отправляемой формы вызова в локальный вызов процедуры на текущий объект. Поскольку реализации объекта иногда проявляют небрежность и не считают нужным показывать, сколько элементов возвращается при возвращении S_OK, правильность установки этого параметра обеспечивает подпрограмма преобразования со стороны объекта:

HRESULT STDMETHODCALLTYPE IEnumDouble_Next_Stub( IEnumDouble *This, ULONG cElems, double *prg, ULONG *pcFetched) {

// call method on actual object

// вызываем метод на текущий объект

HRESULT hr = This->Next(cElems, prg, pcFetched);

// enforce semantics on object-side

// проводим в жизнь семантику на стороне объекта

if (hr == S_OK)

// S_OK implies all elements sent

// S_OK означает, что все элементы посланы

*pcFetched = cElems;

// [length_is] must be explicit

// атрибут [length_is] должен быть явным

return hr;

}

Интерфейсная заглушка всегда будет вызывать данную подпрограмму с ненулевым последним параметром.

Технология с атрибутом [call_as] является полезной при организации преобразований из вызываемой формы в отправляемую по схеме «метод-за-методом». В СОМ также предусмотрена возможность специфицировать определяемые пользователем преобразования для отдельных типов данных при помощью атрибутов определения типов [transmit_as] и [wire_marshal]. Эти три технологии не следует считать основными при разработке интерфейсов; они существуют в основном для поддержки традиционных идиом и типов данных. Еще одним приемом, которым владеет компилятор IDL, является cpp_quote. Ключевое слово cpp_quote разрешает появление в IDL-файле любых операторов C/C++, даже если этот оператор не является допустимым в IDL. Рассмотрим следующее простейшее применение cpp_quote для внедрения определения встраиваемой функции в сгенерированный IDL заголовочный файл:

// surfboard.idl

cpp_quote(«static void Exit(void) { ExitProcess(1); }»)

Имея данный IDL-код, сгенерированный C/C++ заголовочный файл будет просто содержать следующий фрагмент:

// surfboard.h static void Exit(void) { ExitProcess(1); }

Ключевое слово cpp_quote может быть использовано для осуществления различных трюков в компиляторе IDL. Примером этого может служить тип данных REFIID . Фактическим определением IDL для этого типа является typedef IID *REFIID;

В то же время тип C++ определен как typedef const IID& REFIID;

Однако ссылки в стиле C++ не допускаются в IDL. Для решения данной проблемы системный IDL-файл использует следующий прием:

// from wtypes.idl (approx.)

// из файла wtypes.idl (приблизительно)

cpp_quote(«#if 0») typedef IID "REFIID;

// this is the pure IDL definition

// это чисто IDL-определение

cpp_quote(«#endif») cpp_quote(«#ifdef _cplusplus») cpp_quote(«#define REFIID const IID&»)

// C++ definition

// определение C++

cpp_quote(«#else») cpp_quote(«#define REFIID const IID * const»)

// С definition

// определение С

cpp_quote(«#endif»)

Результирующий заголовочный файл C++ выглядит так:

// from wtypes.h (approx.)

// из файла wtypes.h (приблизительно)

#if 0 typedef IID *REFIID;

#endif

#ifdef _cplusplus

#define REFIID const IID&

#else

#define REFIID const IID * const

#endif

Этот несколько гротескный прием необходим, поскольку многие базовые интерфейсы СОМ были определены без учета возможного применения IDL.

Асинхронные методы

Вызовы методов в СОМ являются по умолчанию синхронными. Это означает, что клиентский поток заблокирован до тех пор, пока ответное ORPC-сообщение не получено и не демаршалировано. Такая схема в полной мере демонстрирует, как работает обычный вызов метода в одном потоке (same-thread), и это с полным основанием принято по умолчанию. До появления Windows NT 5.0 не было способа осуществить вызов метода и продолжать обработку одновременно с выполнением метода без явного порождения дополнительных потоков. В версии СОМ Windows NT 5.0 вводится поддержка асинхронного вызова метода. Асинхронность является свойством метода и должна быть выражена в IDL посредством применения атрибута [async_uuid].

Детали этой технологии во время написания данного текста находились в процессе непрерывного изменения. За подробностями обращайтесь к соответствующей документации.

Где мы находимся?

В данной главе обсуждался ряд тем, относящихся к разработке и использованию интерфейсов СОМ. Хотя эта глава никоим образом не содержит исчерпывающего каталога полезных идиом разработки, в ней была сделана попытка решить несколько существенных вопросов, не обсуждавшихся в предшествующих главах книги. По мере того как мое собственное понимание СОМ развивалось в течение двух лет, потребовавшихся для написания этой книги, я пришел к убеждению, что разработчикам следовало бы уделять меньше внимания специфическим возможностям СОМ (таким, как точки стыковки, моникеры, диспетчерские интерфейсы), а вместо этого сосредоточиться на трех китах СОМ: интерфейсы, объекты классов, апартаменты. Вооруженный доскональным пониманием этих трех тем, я твердо верю, что нет вершин, которые нельзя было бы покорить с помощью СОМ.

Проиложение А. Эволюция объектов

Сокращенную версию этого очерка предполагается опубликовать в январском, 1998 года, выпуске Microsoft Systems Journal. Здесь этот очерк включен в приложение, поскольку в нем СОМ рассматривается в исторической перспективе.

Развитие объектно-ориентированного программирования перешло в стадию коммерческого применения в конце 1980-х годов. Центральной темой объектного ориентирования в середине 1980-х было использование классов, которые позволили разработчикам моделировать состояние и поведение как единый абстрактный модуль. Такая упаковка состояния и поведения помогает провести в жизнь модульный принцип через применение инкапсуляции. В классическом объектном ориентировании объекты принадлежали классам, а клиенты манипулировали объектами посредством основанных на классах ссылок. Такая модель программирования принята в большинстве сред и библиотек C++ и Smalltalk тех времен. В то время программисты, придерживающиеся строгого стиля, могли извлечь максимальную пользу из классового подхода, составляя программы на языках, широко применяющих процедуры. Однако действительно широкое распространение объектно-ориентированного программирования наступило только тогда, когда объектное ориентирование стало явно поддерживаться разработчиками языков программирования и сервисных программ. К числу программных сред, сыгравших важнейшую роль в обеспечении успеха объектного ориентирования, относятся оболочка МасАрр фирмы Apple на базе Object Pascal, первые среды SmallTalk фирм ParePlace и Digitalk, а также Turbo C++ фирмы Borland.

109
{"b":"47895","o":1}