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

Скачивание начинается... Если скачивание не началось автоматически, пожалуйста нажмите на эту ссылку.
Жалоба
Напишите нам, и мы в срочном порядке примем меры.
Описание книги "Сущность технологии СОМ. Библиотека программиста"
Описание и краткое содержание "Сущность технологии СОМ. Библиотека программиста" читать бесплатно онлайн.
В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.
},
{
«Apes.Gorilla.1\\CLSID», 0, «{571F1680-CC83-11d0-8C48-0080C73925BA}»
},
};
Имея эту таблицу, весьма несложно осуществить реализацию DllRegisterServer:
STDAPI DllRegisterServer(void)
{
HRESULT hr = SOK;
// look up server's file name
// ищем имя файла сервера
char szFileName[MAXPATH];
GetModuleFileNameA(ghinstDll, szFileName, MAXPATH);
// register entries from table
// регистрируем записи из таблицы
int nEntries = sizeof(gRegTable)/sizeof(*gRegTable);
for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++)
{
const char *pszKeyName = gRegTable[i][0];
const char *pszValueName = gRegTable[i][1];
const char *pszvalue = gRegTable[i][2];
// map rogue value to module file name
// переводим нестандарное значение в имя файла модуля
if (pszValue == (const char*)-1) pszValue = szFileName;
HKEY hkey;
// create the key
// создаем ключ
long err = RegCreateKeyA(HKEYCLASSESROOT, pszKeyName, &hkey);
if (err == ERRORSUCCESS)
{
// set the value
// присваиваем значение
err = RegSetValueExA(hkey, pszVvalueName, 0, REGSZ, (const BYTE*) pszValue, (strlen(pszValue) + 1));
RegCloseKey(hkey);
}
if (err != ERRORSUCCESS)
{
// if cannot add key or value, back out and fail
// если невозможно добавить ключ или значение, то откат и сбой
DllUnregisterServer();
hr = SELFREGECLASS;
}
}
return hr;
}
Соответствующая DllUnregisterServer будет выглядеть так:
STDAPI DllUnregisterServer(void)
{
HRESULT hr = SOK;
int nEntries = sizeof(gRegTable)/sizeof(*gRegTable);
for (int i = nEntries – 1; i >= 0; i-)
{
const char *pszKeyName = gRegTable[i][0];
long err = RegDeleteKeyA(HKEYCLASSESROOT, pszKeyName);
if (err != ERRORSUCCESS) hr = SFALSE; }
return hr;
}
Отметим, что реализация DllUnregisterServer просматривает таблицу с конца, начиная с последней входной точки. Делается это для преодоления ограничения RegDeleteKey, в котором разрешаются только такие ключи, у которых нет подключей, подлежащих удалению. Реализация DllUnregisterServer требует такой организации таблицы, чтобы все подключи каждого ключа появлялись в таблице после входа родительского ключа.
Так как СОМ преобразует CLSID в данный файл реализации, то для объявления в СОМ относящихся к серверу объектов класса необходимо использовать определенные стандартные методики. Для сервера, основанного на исполняемой программе, в СОМ предусмотрены явные API-функции для связывания объектов класса с их CLSID . Эти API-функции мы будем подробно обсуждать в главе 6. Для сервера, основанного на DLL, DLL должна экспортировать известную функцию, которая будет вызываться с помощью CoGetClassObject, когда потребуется объект класса. Эту функцию необходимо экспортировать с использованием файла определения модулей, причем она должна иметь следующий вид:
HRESULT DllGetClassObject(
[in] REFCLSID rclsid,
// which class object?
// какой объект класса?
[in] REFIID riid,
// which interface?
// какой интерфейс?
[out, iidis(riid)] void **ppv);
// put it here!
// разместить его здесь!
Для удобства и эффективности данный сервер может содержать код для более чем одного класса. Первый параметр DllGetClassObject показывает, какой класс в данный момент запрашивается. Второй и третий параметры просто дают функции возможность возвращать типизированный указатель интерфейса для СОМ.
Рассмотрим сервер, реализующий три класса: Gorilla, Chimp и Orangutan. Сервер, возможно, будет содержать шесть отдельных классов C++: три из них создают экземпляры каждого класса, а другие три – объекты класса для каждого класса. В соответствии с этим сценарием, серверная реализация DllGetClassObject будет выглядеть следующим образом:
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
// define a singleton class object for each class
// определяем одноэлементный объект класса
// для каждого класса
static GorillaClass sgorillaClass;
static OrangutanClass sorangutanClass;
static ChimpClass schimpClass;
// return interface pointers to known classes
// возвращаем указатели интерфейсов известных классов
if (rclsid == CLSIDGorilla) return sgorillaClass.QueryInterface(riid, ppv);
else if (rclsid == CLSIDOrangutan)
return sorangutanClass.QueryInterface(riid, ppv);
else if (rclsid == CLSIDChimp) return schimpClass.QueryInterface(riid, ppv);
// if we get to here, rclsid is a class we don't implement,
// so fail with well-known error code
// если мы добрались сюда, то rclsid – это класс, который
// мы не реализуем, поэтому сбой с известным кодом ошибки
*ppv = 0;
return CLASSECLASSNOTAVAILABLE;
}
Заметим, что приведенный код не заботится о том, какой интерфейс объявляется каждым из объектов класса. Он просто отправляет запрос QueryInterface соответствующему объекту класса.
Следующий псевдокод показывает, как API-функция CoGetClassObject устанавливает связь с серверным DllGetClassObject:
// pseudo-code from OLE32.DLL
// псевдокод из OLE32.DLL
HRESULT CoGetClassObject(REFCLSID rclsid, DWORD dwClsCtx, COSERVERINFO *pcsi , REFIID riid, void **ppv)
{
HRESULT hr = REGDBECLASSNOTREG;
*ppv = 0; if (dwClsCtx & CLSCTXINPROC)
{
// try to perform inproc activation
// пытаемся выполнить внутрипроцессную активацию
HRESULT (*pfnGCO)(REFCLSID, REFIID, void**) = 0;
// look in table of already loaded servers in this process
// просматриваем таблицу уже загруженных серверов внутри
// этого процесса pfnGCO = LookupInClassTable(rclsid, dwClsCtx);
if (pfnGCO == 0) {
// not loaded yet!
// еще не загружен!
// ask class store or registry for DLL name
// запрашиваем DLL-имя в хранилище классов или в реестре
char szFileName[MAXPATH];
hr = GetFileFromClassStoreOrRegistry(rclsid, dwClsCtx, szFileName);
if (SUCCEEDED(hr))
{
// try to load the DLL and scrape out DllGetClassObject
// пытаемся загрузить DLL и вытащить DllGetClassObject
HINSTANCE hInst = LoadLibrary(szFileName);
if (hInst == 0) return COEDLLNOTFOUND;
pfnGCO = GetProcAddress(hInst, «DllGetClassObject»);
if (pfnGCO == 0) return COEERRORINDLL;
// cache DLL for later use
// кэшируем DLL для дальнейшего использования InsertInClassTable(rclsid, dwClsCtx, hInst, pfnGCO);
}
}
// call function to get pointer to class object
// вызываем функцию для получения указателя на объект класса
hr = (*pfnGCO)(rclsid, riid, ppv);
}
if ((dwClsCtx & (CLSCTXLOCALSERVER | CLSCTXREMOTESERVER)) && hr == REGDBECLASSNOTREG)
{
// handle out-of-proc/remote request
// обрабатываем внепроцессный/удаленный запрос
}
return hr;
}
Отметим, что реализация CoGetClassObject является единственным местом, откуда вызывается DllGetClassObject . Чтобы укрепить это обстоятельство, компоновщики в модели СОМ выдадут предупреждение в случае, если входная точка DllGetClassObject экспортируется без использования ключевого слова private в соответствующем файле определения модулей:
// from APELIB.DEF
// из APELIB.DEF LIBRARY
APELIB EXPORTS DllGetClassObject private
Фактически в модели СОМ компоновщики предпочитают, чтобы во всех связанных с СОМ точках входа использовалось это ключевое слово.
Обобщения
В предыдущем примере интерфейс IApeClass рассматривался как интерфейс уровня класса, специфический для классов, которые объявляют интерфейс IАре из своих экземпляров. Этот интерфейс позволяет клиентам создавать новые объекты или находить существующие, но в любом случае результирующие объекты должны реализовывать интерфейс IАре . Если бы новый класс хотел разрешить клиентам создавать или находить объекты, несовместимые с IApe , то объект этого класса должен был бы реализовывать другой интерфейс. Поскольку создание и поиск объектов являются общими требованиями, которые большинство классов хотели бы поддерживать, СОМ определяет стандартные интерфейсы для моделирования поиска и создания объектов унифицированным образом (generically). Один стандартный интерфейс для поиска объектов назван IOleItemContainer:
// from oleidl.idl из oleidl.idl
[ object, uuid(0000011c-0000-0000-C000-000000000046) ]
interface IOleItemContainer : IOleContainer {
// ask for object named by pszItem
// запрашиваем объект, именованный
pszItem HRESULT Get0bject(
[in] LPOLESTR pszItem,
// which object? какой объект?
[in] DWORD dwSpeedNeeded,
// deadline
[in, unique] IBindCtx *pbc,
// binding info информация о связывании
[in] REFIID riid,
// which interface? какой интерфейс?
[out, iidis(riid)] void **ppv);
// put it here! разместим его здесь!
// remaining methods deleted for clarity
// остальные методы удалены для ясности
}
Отметим, что метод GetObject позволяет клиенту задавать тип результирующего интерфейсного указателя. Действительный класс результирующего объекта зависит от контекста и конкретной реализации IOleItemContainer . Следующий пример запрашивает объект класса Gorilla найти объект под именем «Ursus»:
HRESULT FindUrsus(IApe * &rpApe)
{
// bind a reference to the class object
// связываем ссылку с объектом класса
rpApe = 0;
IOleItemContainer *poic = 0;
HRESULT hr = CoGetClassObject(CLSIDGorilla, CLSCTXALL, 0, IIDIOleItemContainer, (void**)&poic);
Подписывайтесь на наши страницы в социальных сетях.
Будьте в курсе последних книжных новинок, комментируйте, обсуждайте. Мы ждём Вас!
Похожие книги на "Сущность технологии СОМ. Библиотека программиста"
Книги похожие на "Сущность технологии СОМ. Библиотека программиста" читать онлайн или скачать бесплатно полные версии.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
Отзывы о "Дональд Бокс - Сущность технологии СОМ. Библиотека программиста"
Отзывы читателей о книге "Сущность технологии СОМ. Библиотека программиста", комментарии и мнения людей о произведении.