Добавить в цитаты Настройки чтения

Страница 185 из 372

                            free(pszName);

                            if (SysStringLen(bstrDocString) > 0)

                            {

                                    pszDoc = (char*)malloc(2*SysStringLen(bstrDocString));

                                    wcstombs(pszDoc, bstrDocString, 2*SysStringLen(bstrDocString));

                                     cout <<": " << pszDoc;

                                    free(pszDoc);

                             }

                             cout << endl;

                             SysFreeString(bstrName);

                              SysFreeString(bstrDocString);

                         }

                     }

                     pTypeLib — > Release ();

        }

        CoUnitialize ();

         return 0;

}

Для определенности рассматривается библиотека типов, сформированная по IDL-файлу PubInProcServerTypeInfo.idl. В константе LIBID_PubinProcServer задается GUID данной библиотеки типов.

Функция LoadRegTypeLib () загружает библиотеку типов с заданным GUID и, в случае успеха, в параметре pTypeLib возвращает указатель на интерфейс iTypeLib. В данном случае нам достаточно этого интерфейса, так как интересующая нас информация является информацией общего характера о библиотеке типов. Второй (старший номер версии) и третий (младший номер версии) параметры определяют ограничения на номер версии загружаемой библиотеки типов: загружается библиотека с указанной версией; если такой нет, то загружается библиотека, у которой старший номер версии равен запрашиваемому, а младший — максимальный из доступных и не меньше запрашиваемого. Если данное ограничение не выполняется, то возвращается ошибка. Четвертый параметр в данном случае указывает на то, что при построении описания библиотеки использовался нейтральный естественный язык.

В регистре всему этому соответствует ключ

НКЕ Y_CLASSЕS_ROOT TipeLib

{68A702C2-8283-22d5-98C7-000001223694} 1.0 0 Win32

значением которого является путь К файлу PubInProcServerTypeInfo.tlb.

В данной программе вызываются всего два метода из всего множества методов интерфейса ITypeLib:

• GetTypeInfoCount ()

Возвращает число описаний типов в библиотеке

• GetDocumentation ()

По номеру описания типа позволяет получить имя типа, его описание (helpstring), идентификатор контекста помощи и путь к файлу помощи. Подставляя NULL вместо определенного возвращаемого параметра, можно отказаться от получения соответствующей информации. Нумерация описанных в библиотеке типов начинается с нуля. Для получения информации о самой библиотеки нужно положить индекс равным — 1.

Вся строковая информация в библиотеке типов хранится в строках типа BSTR. Функция GetDocumentation сама выделяет под них память, а клиент должен ее освободить





SysFreeString(bstrName);

SysFreeString(bstrDocString);

Для перехода к ANSI строкам приходится выделять буфер подходящего размера и выполнять преобразование из BSTR в ANSI с помощью wcstombs.

Результат работы программы:

-1: PubinProcServer: PubinProcServer with TypeLib

0: CoBook

1: IBook: Book

2: IPub: Base publication

3: CoJournal

4: IJournal: Journal

Под индексом -1 приведены имя самой библиотеки типов (как она была описана в IDL) и соответствующая строка документации (helpstring).

Под индексами от 0 до 4 идут имена типов — коклассов и их интерфейсов. Строка документации приводится только для тех из них, для которых она имеется в IDL-файле.

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

Прозрачность местоположения

DLL сервер в суррогатном процессе

Как уже не раз говорилось ранее, один из важнейших принципов СОМ — прозрачность местоположения. Иными словами, на код клиента не должно оказывать влияние конкретное местоположение сервера (конечно при условии, что этот сервер зарегистрирован в реестре системы).

Ранее мы построили и зарегистрировали сервер в процессе клиента PubInProcServer и самого клиента PubClient. Сервер, загружаемый в процесс клиента, обладает как положительными, так и отрицательными свойствами. К положительным можно прежде всего отнести быстродействие. А к отрицательным, например, неизолированность сервера от клиента, что приводит к тому, что клиент "вылетает" при сбое сервера.

В рамках архитектуры СОМ наряду с сервером в процессе клиента можно строить локальный сервер (исполняется в отдельном процессе на машине клиента) и удаленный сервер (исполняется на удаленном компьютере). При наличии уже реализованного сервера в виде сервера в процессе клиента, его можно превратить в сервер, исполняемый вне процесса клиента, загружая в специальный процесс — DLL суррогат. Имеется стандартный DLL суррогат (dllhost.ехе), который можно использовать для этой цели.

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

Итак, далее мы рассмотрим размещение сервера PubInProcServer в суррогатном процессе.

Для размещения DLL сервера в суррогатном процессе достаточно сделать несколько дополнительных настроек в реестре, связанных с идентификатором приложения — AppID.

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

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

В качестве GUID для приложения можно взять GUID одного из классов, входящих в состав приложения. Например, первого класса, описанного в idl-файле.

Для занесения информации о AppID надо в реестре под ключом HKEY_CLASES_ROOT AppID завести новый раздел с GUID данного приложения. В этом разделе можно задавать различные атрибуты, управляющие доступом к приложению и т. д. Мы здесь зададим параметр с именем DllSurrogate и с пустым значением. Это означает, что приложение с данным AppID должно выполняться в стандартном суррогатном процессе (dllhost. ехе).

Теперь надо связать все входящие в приложение классы с данным AppID. Для этого под ключом HKEY_CLASES_ROOT CLSID clsid_данного_класса надо завести дополнительный строковый параметр AppID со значением равным AppID нашего приложения. Это надо повторить для всех классов нашего приложения.

Клиент PubCiient был жестко ориентирован на работу с сервером в процессе клиента. Эта ориентация задавалась при активации фабрики класса. Например,

hr = CoGetClassObject(CLSID_CoBook, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void**)&pBF);