MessageBox (0, buff, "Interface ISay:", MB_OK);
return S_OK;
}
HRESULT __stdcall CoSay::SetWord(BSTR word)
{
SysReAllocString (&m_word, word); // Повторное выделение памяти
return S_OK;
}
Класс, поддерживающий интерфейс готов. Теперь следует сделать доступным для пользователей COM-объекта весь DLL-сервер, в котором живет ко-класс CoSay. Минимально, COM DLL может экспортировать только одну функцию DllGetClassObject. Обычно ее сопровождают еще три функции. В данный момент мы рассматриваем лишь минимальный набор. DLL должна создать COM-объект и позволить работать с ним, получив (то есть записав по адресу ppv) адрес зарегистрированного интерфейса. Так как в предложении дважды использовано слово адрес, то параметр ppv имеет тип void**. Введите эту функцию в конец файла MyCom.cpp.
STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void** ppv)
{
if (rclsid != CLSID_CoSay) // Если идентификатор класса задан неправильно,
return CLASS_E_CLASSNOTAVAILABLE; // возвращаем код ошибки с указанием причины неудачи
CoSay *pSay = new CoSay; // Создаем объект ко-класса
HRESULT hr = pSay->QueryInterface (riid, ppv); // Запрошиваем интерфейс (его адрес)
if (FAILED(hr))
delete pSay;
return hr;
}
Макроподстановка STDAPI при разворачивании превратится в
extern "C" HRESULT __stdcall
Работа по опознаванию объектов идет с идентификаторами: класса (rclsid) и интерфейса (riid). Это является, как считают апологеты COM, одной из самых важных черт, которые вносят небывалый уровень надежности в функционирование COM-приложений. Весьма спорное утверждение, так как центром всей вселенной как разработчика, так и пользователя становится Windows-реестр, который открыт всем ветрам — как случайным, так и преднамеренным воздействиям со стороны человека и программы. Однако, следует согласиться с тем, что уникальная идентификация снимает проблему случайного (но весьма вероятного) совпадения имен интерфейсов, разработанных в разных частях света. То же относится и к именам классов, библиотек типов и т. д.
Для успешной работы DLL следует добавить к проекту файл ее описания (DEF-файл). Этот способ является альтернативным и, возможно, более простым, чем использование описателей __declspec(dllexport) для экспортируемых функций. DEF-файл сопровождает DLL и содержит список функций, экспортируемых ею. Создайте новый файл MyCom.def и введите в него такие строки:
LIBRARY "MYCOM.dll"
EXPORTS
DllGetClassObject PRIVATE
Заметим, что теперь нет необходимости нумеровать экспортируемые функции (как делалось ранее).
DllGetClassObject @1 PRIVATE
При наличии DEF-файла компоновщик создает (кроме основного файла библиотеки MyCom.dll) еще два необходимых файла: MyCom.lib (заголовов экспортируемых функций) и MyCom.exp. При отсутствии последних двух файлов система не сможет обратиться к функции DllGetClassObject, а следовательно и к нашему COM-объекту CoSay. Для того, чтобы DEF-файл участвовал в процессе сборки DLL, в рамках 6-й студии его достаточно было лишь подключить к проекту. Этого шага, однако, недостаточно в рамках 7-й студии. Надо сделать еще одну установку.
1. Установите фокус на строке MyCom в окне Solution Explorer и дайте команду View4Propertiy Pages;
2. Раскойте узел Linker4Input в дереве левого окна диалога MyCom Property Pages и введите имя MyCom.def в строку Module Definition File списка свойств.
3. Нажмите кнопку OK.
Следующим шагом вы должны зарегистрировать сервер, то есть внести в реестр Windows записи, которые регистрируют факт существования и местоположение DLL. При работе с ATL это действие будет автоматизировано, но сейчас создайте и подключите к проекту еще один файл MyCom.reg, формат которого соответствует командам регистрации, воспринимаемых редактором реестра RegEdit.exe.
В версии студии, с которой я имею дело, в списке типов добавляемых файлов отсутствует тип REG. Поэтому создайте текстовый файл MyCom.txt и запишите его как MyCom.reg.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.