Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Деревянко_БС ЭВМ

.pdf
Скачиваний:
66
Добавлен:
31.05.2015
Размер:
3.6 Mб
Скачать

1.2.2. Строки в модели СОМ

Особенности применения строк в СОМ связаны с тем, что, во-первых, СОМ – независимая от языка технология программирования, а строки в разных языках представляются не одинаково, и, во-вторых, СОМ может применяться на различных операционных системах, где строки тоже представляются различным образом.

Стандартные строковые типы СОМ: OLECHAR и

BSTR.

Тип данных OLECHAR определяется в <wtypes.h> и применяется для клиентов на языках С/С++. В зависимости от платформы, OLECHAR:

1)это – wchar_t (Unicode) – если платформа Win32 и не задано преобразование OLE – ANSI;

2)это – char (ANSI) – в других случаях.

Если при создании текстовой константы указать префикс L, то строится строка Unicode, например, L "строка".

Используется также макрос OLESTR, преобразующий символы в строку Unicode в нешестнадцатиразрядных приложениях.

Тип данных BSTR – это строка Unicode фиксированной длины и с NULL на конце. Определение BSTR:

typedef OLECHAR* BSTR;

Методы, работающие с BSTR, имеют префикс Sys (system string).

Функции преобразования между строками ANSI и Unicode:

MultiByteToWideChar() и

WideCharToMultiByte().

Это функции API для Win32. Библиотека языка С имеет эквивалентные функции: mbstowcs и wcstombs.

21

1.2.3. Создание объектов СОМ

Речь идет о том, что клиент должен уметь создавать объекты внутри исполняемого сервера, причем сервер может располагаться территориально в любом месте (связь между клиентом и сервером СОМ может быть внутрипроцессная, локальная и удалённая).

Независимо от языка и местоположения сервера для создания объектов СОМ предоставляет стандартный интерфейс IClassFactory. Второй интерфейс IClassFactory2, создающий объекты СОМ, обеспечивает лицензионную поддержку модели СОМ.

Новый термин СОМ – объект класса.

Объект класса – это объект СОМ, реализующий интерфейс IClassFactory (или IClassFactory2).

Объекты класса называются также фабриками класса. Объекты класса существуют только для создания объектов СОМ. Объекты класса имеют взаимнооднозначное соответствие с объектами, которые они создают. Объекты класса не могут создавать набор объектов СОМ.

Через интерфейс IClassFactory клиент получает возможность создать требуемый ему объект (экземпляр кокласса) в исполняемом сервере. Фабрика класса создает соответствующий объект, далее СОМ запрашивает нужный интерфейс из объекта и возвращает его клиенту. Фабрику класса можно рассматривать как аналог оператора new.

Основным методом интерфейса IClassFactory является CreateInstance(), создающий требуемый кокласс от имени запрашивающего клиента. Этот метод имеет 3 параметра:

первый параметр используется в связи с СОМ аг-

22

регацией, пока устанавливаем в NULL;

второй параметр - IID интерфейса, который клиент хочет получить из кокласса после его создания (это либо IID_Unknown, либо один из пользовательских интерфейсов);

третий параметр, void**, служит для размещения указателя интерфейса, вытащенного из кокласса.

Пример определения объекта класса (фабрики клас-

са):

сlass CoCarClassFactory: public IClassFactory

{

 

public:

 

CoCarClassFactory( );

//конструктор

virtual ~CoCarClassFactory( ); //деструктор

//IUnknown

STDMETHODIMP QueryInterface(REFIID riid, void* * pIFace);

STDMETHODIMP_ (ULONG) AddRef(); STDMETHODIMP_ (ULONG) Release();

//IClassFactory

STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid, void** ppv ); Private:

ULONG m_refCount;

//обнуляется в конструкто-

ре

 

};

 

23

Пример создания кокласса

Создадим объект CoCar и запросим нужный интерфейс.

Класс CoCarClassFactory – объект класса, используется для создания объекта кокласса CoCar. Ме-

тод

CreateInstance

принадлежит

интерфейсу

IClassFactory (классу CoCarClassFactory).

STDMETHODIMP

CoCarClassFactory

:: Cre-

ateInstance (LPUNKNOWN pUnkOuter, REFIID

 

 

 

riid, void** ppv );

{

 

 

 

 

 

. . .

 

 

 

 

CoCar

 

pCarObj = NULL;

 

HRESULT

hr;

 

 

 

pCarObj

= new CoCar

//Создание объекта

hr =

pCarObj

-> QueryInterface

(riid,

ppv);

//Интерфейс

 

 

if (Failed (hr)

//Ошибка delete pCarObj;

return hr;

}

Метод LockServer интерфейса IClassFactory

даёт клиенту возможность удерживать сервер в памяти, даже если в данный момент в сервере отсутствуют активные объекты. Делается это в целях оптимизации клиента.

Каждый кокласс, входящий в сервер, оснащается уникальным CLSID; причём сама фабрика класса не получает CLSID. Каждый СОМ-объект также должен иметь уникальный идентификатор.

Для создания фабрики класса используется метод

24

DllGetClassObject. Он возвращает клиенту указатель интерфейса IClassFactory.

Пример создания фабрики класса

Здесь создается объект класса (фабрика класса) CoCarClassFactory, который будет строить экземпляры класса CoCar.

STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void** ppv)

{

HRESULT hr;

CoCarClassFactory* pCFact = NULL; if (rclsid != CLSID_CoCar)

return CLASS_E_CLASSNOTAVAILABLE;

// rclsid – определяет, какой класс со-

здать

 

 

 

pCfact

=

new

CoCarClassFactory;

//Создание

фабрики класса

hr = pCFact -> QueryInterface(riid,

ppv);

// Интерфейс

 

. . .

 

 

 

return

hr;

 

 

}

 

 

 

Метод DllCanUnloadNow определяет, можно ли выгружать данный DLL-сервер из памяти. В отношении сервера ведётся два счётчика:

число активных объектов сервера на данный момент определяется конструктором и деструктором объекта СОМ;

число блокировок, определяемых методом

IClassFactory :: LockServer.

25

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

Два последних метода (функции) являются элементами библиотеки DLL. Стандартно они описываются с помощью DEF-файла, который должен быть включён в проект. Имя библиотеки совпадает с именем рабочей области проекта.

LIBRARY “CARSERVER”

 

 

EXPORTS

 

 

DllGetClassObject

@1

PRIVATE

DllCanUnloadNow

@2

PRIVATE

1.2.4. Регистрация СОМ-сервера

Реестр системы

Реестр системы (system registry) − это локальная системная база данных, определяющая (среди прочего) связанную с СОМ информацию для данного компьютера. Для редактирования реестра используется программа regedit.exe.

Реестр разбит на ряд узлов, называемых ульями (hires). При работе с СОМ самым важным узлом является

HKEY_CLASSES_ROOT (сокращенно HKCR). Точки вхо-

да под ульями называются ключами.

Строки в улье HKCR, расположенные после всех расширений (..., .z, .zip), относятся к СОМ и называются программными идентификаторами (ProgID).

ProgID – это просто текстовое отображение CLSID и используется для идентификации объекта (поиска пути к

26

объекту) СОМ, находящегося в каком-либо сервере. Каждый список ProgID имеет свой подключ, соответствующий CLSID, и может иметь подключ CurVer (current version).

Стандартный формат ProgID для кокласса: “ИмяСервера.ИмяКокласса.Версия”.

Библиотека СОМ предоставляет две функции, позволяющие получить ProgID по заданному CLSID (CLSIDFromProgID) и наоборот – получить CLSID по за-

данному ProgID (ProgIDFromCLSID).

Данные реестра использует rpcss.exe – менеджер управления сервисом SCM (читается «скум»). SCM загружает сервер в память при этом он отыскивает в реестре физический путь к СОМ-серверу, используя следующие под-

ключи CLSID:

ProgID – соответствует ProgID кокласса; InРrocServer32 – задаёт путь к DLL – внутри-

процессному СОМ-серверу;

LocalServer32 – задаёт путь к файлу ЕХЕ.

Регистрация СОМ-сервера

Каждый внутрипроцессный сервер должен уметь вставлять и удалять информацию из реестра системы. Для этого используются две функции:

DllRegisterServer() и DllUnregisterServer().

Более простой способ занесения информации в системный реестр заключается в использовании файла с расширением .reg.

При создании такого файла должны выполняться следующие условия. В первой строке файла должно быть

27

слово REGEDIT. Вокруг знака равенство ( = ) должны быть пробелы. Вокруг символов \ не должно быть пробелов. Путь к серверу DLL записывается обычным образом, например,

D:\ProgATL\Debug\CarInProcServer.dll

Во всех трех строках следующего примера содержится одно и то же значение СLSID.

Пример файла *.reg :

REGEDIT

HKEY_CLASSES_ROOT\CarInProcServer.CoCar\CLSID = {CLSID из макроса DEFINE_GUID — это PROGID}

HKEY_CLASSES_ROOT\CLSID\{СLSID кокласса} =

CarInProcServer.CoCar

 

 

HKEY_CLASSES_ROOT\CLSID\{СLSID

кокласса

}\InРrocServer32 =

путь к серверу_DLL

1.2.5. Разработка клиента СОМ

Выше рассматривалась разработка внутрипроцессного СОМ-сервера. Теперь рассмотрим библиотечные вызовы СОМ для доступа к этому СОМ-серверу. Вне зависимости от языка программирования на глубинном уровне в клиенте и в сервере используется одна и та же последовательность вызовов. Вызываемые функции СОМ содержатся в модуле ole32.dll.

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

28

вызвать CoUninitialize() для выполнения очистки. Далее следует загрузить сервер, создать новый объ-

ект СОМ и получить указатель IClassFactory созданной фабрики класса.

Клиентский процесс, использующий

 

внутрипроцессный сервер

 

 

DL

 

Client.EX

CoHex

CoHe

CF

 

x

 

ole32.dll

 

Менеджер управления сервисом (SCM, или RPCSS.EXE)

Рис. 1.6. SCM, ole32.dll, клиент и сервер

Для этого используется функция CoGetClassObject с параметрами:

1)REFCLSID rclsid – это CLSID создаваемого кокласса, например, СLSID_CoCar. По информации, ранее записанной в системный реестр, SCM отыскивает путь

кисполняемому файлу и загружает сервер;

2)DWORD dwClsContext – контекст класса сер-

вера, позволяет определить, с каким сервером желаем работать:

CLSCTX_INPROC_SERVER – внутрипроцессный; CLSCTX_LOCAL_SERVER – локальный; CLSCTX_REMOTE_SERVER – удалённый;

29

CLSCTX_SERVER – SCM находит ближайший сервер.

3) COSERVERINFO pServerInfo – информация об удалённой машине (имя машины, параметры безопасности доступа); NULL, если сервер не удалённый;

4)

REFIID

riid – IID запрашиваемого интер-

фейса, здесь IID_IСlassFactory;

5)

LPVOID**

ppv – указатель на интерфейс, за-

прошенный в riid, например, (void**) &pICF.

Это был последний параметр в CoGetClassObject().

Пример.

Получаем указатель интерфейса фабрики класса.

hr = CoGetClassObject(CLSID_CoCar, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void**) &pICF);

Используем этот указатель на фабрику класса для создания экземпляра кокласса.

hr = pICF ->CreateInstance (NULL,

IID_IСreateCar, (void* *) &pICreateCar);

Итак, создан объект CoCar и получен указатель на интерфейс IСreateCar. Теперь можно выполнять методы этого интерфейса и запрашивать другие интерфейсы.

По завершении работы важно не забывать вызывать Release() для каждого полученного указателя интерфейса.

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]