Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
0/0

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

Уважаемые читатели!
Тут можно читать бесплатно Сущность технологии СОМ. Библиотека программиста - Дональд Бокс. Жанр: Программирование. Так же Вы можете читать полную версию (весь текст) онлайн книги без регистрации и SMS на сайте Knigi-online.info (книги онлайн) или прочесть краткое содержание, описание, предисловие (аннотацию) от автора и ознакомиться с отзывами (комментариями) о произведении.
Описание онлайн-книги Сущность технологии СОМ. Библиотека программиста - Дональд Бокс:
В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.
Читем онлайн Сущность технологии СОМ. Библиотека программиста - Дональд Бокс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 16 17 18 19 20 21 22 23 24 ... 95

// Inttable.h (заголовочный файл, специфический для данной книги)

#define BASEOFFSET(ClassName, BaseName) (DWORD(staticcast<BaseName*>(reinterpretcast <ClassName*>(0x10000000))) – 0х10000000)

#define BEGININTERFACETABLE(ClassName) typedef ClassName ITCls; const INTERFACEENTRY *GetInterfaceTable(void) { static const INTERFACEENTRY table [] = {

#define IMPLEMENTSINTERFACE(Itf) {&IID##Itf,ENTRYISOFFSET,BASEOFFSET(ITCls,Itf)},

#define IMPLEMENTSINTERFACEAS(req, Itf) {&IID##req,ENTRYISOFFSET, BASEOFFSET(ITCls, Itf)},

#define ENDINTERFACETABLE() { 0, 0, 0 } }; return table; }

Все, что требуется, – это стандартная функция, которая может анализировать интерфейсную таблицу в ответ на запрос QueryInterface. Такая функция содержится в файле Inttable.h:

// inttable.cpp (book-specific source file)

// inttable.h (заголовочный файл, специфический для данной книги)

HRESULT InterfaceTableQueryInterface(void *pThis, const INTERFACEENTRY *pTable, REFIID riid, void **ppv)

{

if (InlineIsEqualGUID(riid, IIDIUnknown))

{

// first entry must be an offset

// первый элемент должен быть смещением

*ppv = (char*)pThis + pTable->dwData;

((Unknown*) (*ppv))->AddRef () ;

// A2

return SOK;

} else

{

HRESULT hr = ENOINTERFACE;

while (pTable->pfnFinder)

{

// null fn ptr == EOT

if (!pTable->pIID || InlineIsEqualGUID(riid,*pTable->pIID))

{

if (pTable->pfnFinder == ENTRYISOFFSET)

{

*ppv = (char*)pThis + pTable->dwData;

((IUnknown*)(*ppv))->AddRef();

// A2

hr = SOK;

break;

} else

{

hr = pTable->pfnFinder(pThis, pTable->dwData, riid, ppv);

if (hr == SOK) break;

}

}

pTable++;

}

if (hr!= SOK)

*ppv = 0;

return hr;

}

}

Получив указатель на запрошенный объект, InterfaceTableQueryInterface сканирует таблицу в поисках элемента, соответствующего запрошенному IID, и либо добавляет соответствующее смещение, либо вызывает соответствующую функцию. Приведенный выше код использует усовершенствованную версию IsEqualGUID, которая генерирует несколько больший код, но результаты по скорости примерно на 20-30 процентов превышают данные по существующей реализации, которая не управляется таблицей. Поскольку код для InterfaceTableQueryInterface появится в исполняемой программе только один раз, это весьма неплохой компромисс.

Очень легко автоматизировать поддержку СОМ для любого класса C++, основанную на таком табличном управлении, простым использованием С-препроцессора. Следующий фрагмент из заголовочного файла impunk.h определяет QueryInterface, AddRef и Release для объекта, использующего интерфейсные таблицы и расположенного в динамически распределяемой области памяти:

// impunk.h (book-specific header file)

// impunk.h (заголовочный файл, специфический для данной книги)

// AUTOLONG is just a long that constructs to zero

// AUTOLONG – это просто long, с конструктором,

// устанавливающим значение в О

struct AUTOLONG

{

LONG value;

AUTOLONG (void) : value (0) {}

};

#define IMPLEMENTUNKNOWN(ClassName)

AUTOLONG mcRef;

STDMETHODIMP QueryInterface(REFIID riid, void **ppv){

return InterfaceTableQueryInterface(this,

GetInterfaceTable(), riid, ppv);

}

STDMETHODIMP(ULONG) AddRef(void) {

return InterlockedIncrement(&mcRef.value);

}

STDMETHODIMP(ULONG) Release(void) {

ULONG res = InterlockedDecrement(&mcRef.value) ;

if (res == 0)

delete this;

return res;

}

Настоящий заголовочный файл содержит дополнительные макросы для поддержки объектов, не находящихся в динамически распределяемой области памяти.

Для реализации примера PugCat, уже встречавшегося в этой главе, необходимо всего лишь удалить текущие реализации QueryInterface, AddRef и Release и добавить соответствующие макросы:

class PugCat : public IPug, public ICat

{

protected:

virtual ~PugCat(void);

public: PugCat(void);

// IUnknown methods

// методы IUnknown

IMPLEMENTUNKNOWN (PugCat)

BEGININTERFACETABLE(PugCat)

IMPLEMENTSINTERFACE(IPug)

IMPLEMENTSINTERFACE(IDog)

IMPLEMENTSINTERFACEAS(IAnimal,IDog)

IMPLEMENTSINTERFACE(ICat)

ENDINTERFACETABLE()

// IAnimal methods

// методы IAnimal

STDMETHODIMP Eat(void);

// IDog methods

// методы IDog

STDMETHODIMP Bark(void);

// IPug methods

// методы IPug

STDMETHODIMP Snore(void);

// ICat methods

// методы ICat

STDMETHODIMP IgnoreMaster(void);

};

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

Типы данных

Все интерфейсы СОМ должны быть определены в IDL. IDL позволяет описывать довольно сложные типы данных в стиле, не зависящем от языка и платформы. Рисунок 2.6 показывает базовые типы, которые поддерживаются IDL, и их отображения в языки С, Java и Visual Basic. Целые и вещественные типы не требуют объяснений. Первые «интересные» типы данных, встречающиеся при программировании в СОМ, – это символы и строки.

Все символы в СОМ представлены с использованием типа данных OLECHAR. Для Windows NT, Windows 95, Win32s и Solaris OLECHAR – это просто typedef для типа данных С wchar_t. Специфика других платформ описана в соответствующих документациях. Платформы Win32 используют тип данных wchar_t для представления 16-битных символов Unicode[1]. Поскольку типы указателей в IDL созданы так, что указывают на одиночные переменные, а не на массивы, то IDL вводит атрибут [string], чтобы подчеркнуть, что указатель указывает на массив-строку с завершающим нулем:

HRESULT Method([in, string] const OLECHAR *pwsz);

Для определения строк и символов, совместимых с OLECHAR, в СОМ введен макрос OLESTR, который приписывает букву L перед строковой или символьной константой, информируя таким образом компилятор о том, что эта константа имеет тип wchar_t. Например, правильным будет такой способ инициализировать указатель OLECHAR с помощью строкового литерала:

const OLECHAR *pwsz = OLESTR(«Hello»);

Под Win32 или Solaris это эквивалентно

const wchar_t *pwsz = L"Hello";

Первый вариант предпочтительней, так как он будет надежно компилироваться на всех платформах.

Поскольку часто возникает необходимость копировать строки на основе типа wchar_t в обычные буфера на основе char, то динамическая библиотека С предлагает две процедуры для преобразования типов:

size_t mbstowcs(wchar_t *pwsz, const char *psz, int cch);

size_t wcstombs(char *psz, const wchar_t *pwsz, int cch);

Эти две процедуры работают аналогично динамической С-процедуре strncpy, за исключением того, что в эти процедуры как часть операции копирования включено расширение или сужение строки. Следующий код показывает, как параметр метода, размещенный в OLECHAR, можно скопировать в элемент данных, размещенный в char:

class BigDog : public ILabrador

{

char m_szName[1024] ;

public:

STDMETHODIMP SetName(/* [in,string]*/ const OLECHAR *pwsz)

{

HRESULT hr = S_OK;

size_t cb = wcstombs(m_szName, pwsz, 1024);

// check for buffer overflow or bad conversion

// проверяем переполнение буфера или неверное преобразование

if (cb == sizeof(m_szName) || cb == (size_t)-1)

{

m_szName[0] = 0; hr = E_INVALIDARG;

}

return hr;

}

};

Этот код является довольно простым, хотя программист должен осознавать, что используются два различных типа символов. Несколько более сложный (и чаще встречающийся) случай – преобразование между типами данных OLECHAR и TCHAR из Win32. Так как OLECHAR условно компилируется как char или wchar_t, то при реализации метода необходимо должным образом рассмотреть оба сценария:

class BigDog : public ILabrador

{

TCHAR m_szName[1024];

// note TCHAR-based string

// отметим строку типа TCHAR

public:

STDMETHODIMP SetName( /*[in,string]*/ const OLECHAR *pwsz)

{

HRESULT hr = S_OK;

#ifdef UNICODE

// Unicode build (TCHAR == wchar_t)

// конструкция Unicode (TCHAR == wchar_t)

wcsncpy(m_szName, pwsz, 1024);

// check for buffer overflow

// проверка на переполнение буфера

if (m_szName[1023] != 0)

{

m_szName[0] = 0;

hr = E_INVALIDARG;

}

#else

// Non-Unicode build (TCHAR == char)

// не является конструкцией Unicode (TCHAR == char)

size_t cb = wcstombs(m_szName, pwsz, 1024);

// check for buffer overflow or bad conversion

// проверка переполнения буфера или ошибки преобразования

if (cb == sizeof(m_szName) || cb == (size_t)-1)

{

m_szName[0] =0;

hr = E_INVALIDARG; 

#endif return hr;

}

};

Очевидно, операции с преобразованиями OLECHAR в TCHAR значительно сложнее. Но, к сожалению, это самый распространенный сценарий при программировании в СОМ на базе Win32.

1 ... 16 17 18 19 20 21 22 23 24 ... 95
На этой странице вы можете бесплатно читать книгу Сущность технологии СОМ. Библиотека программиста - Дональд Бокс бесплатно.

Оставить комментарий

Рейтинговые книги