Пакет Vstudio7

       

Сейчас мы займемся разработкой DLL



Разработка сервера

Сейчас мы займемся разработкой DLL СОМ-сервера, выполняемого в пространстве процесса другого (клиентского) приложения. Для того чтобы понять, что кроется за этой вывеской, мы для начала создадим минимально-простой СОМ-объект и при этом специально не будем пользоваться какими-либо библиотеками или инструментами Studio.Net.

Наш объект будет предоставлять миру только один интерфейс isay, инкапсулирующий два метода: Say и SetWord. Первый метод выводит текстовую строку типа BSTR в окно типа MessageBox, а второй — позволяет изменять эту строку. Тип BSTR в Win32 является адресом двухбайтовой Unicode-строки. Его советуют использовать в СОМ-объектах для обеспечения совместимости с клиентскими приложениями, написанными на других языках.

Я надеюсь, что логика, заложенная в этом простом приложении, поможет вам не терять нить повествования при разработке следующего, более сложного объекта с помощью ATL. Использование ATL и инструментов Studio.Net упрощают разработку СОМ-объектов, но скрывают суть происходящего, вызывая иногда чувство досады и неудовлетворенности. С помощью мастера AppWizard создайте шаблон приложения типа Win32 Dynamic-Link Library (Динамически компонуемая библиотека Win32) под именем МуСот.

  1. Дайте команду File > New * Project. В диалоге New Project выберите шаблон Win32 Project под именем МуСот и нажмите ОК.
  2. В окне Win32 Application Wizard откройте вкладку Application Settings, установите переключатель Application Type в положение DLL, включите флажок Empty Project и нажмите кнопку Finish.


  3. Подключите к проекту новый файл типа C/C++ Header File. Для этого дайте команду Project > Add ' New Item. В диалоге Add New Item выберите шаблон Header File (.h), а в поле Name задайте имя interfaces.h и нажмите кнопку Open
  4. Введите в этот файл нижеследующие директивы препроцессора и описание интерфейса ISay.
Примечание 1
Примечание 1



Это же действие можно выполнить более сложным способом, но зато сход-ным с тем, как это делалось в Visual Studio 6. Дайте команду File > New > File, выберите тип файла и нажмите кнопку Open. Кроме этих действий придется записать новый файл в папку с проектом и подключить его. Для этого используется команда Project > Add Existing Item с последующим поиском файла. Альтернативой этому является перетаскивание существующего файла в окне Solution Explorer из папки Resource Files в папку Header Files.

//=== Эти директивы нужны для того, чтобы не допустить

//=== повторное подключение файла

#if !defined(MY_ISAY_INTERFACE)

#define MY__ISAY_INTERFACE

#pragma once

//====== Для того, чтобы были доступны COM API

#include <windows.h>

//====== Для того, чтобы был виден lUnknown

#include <initguid.h>

// Интерфейс ISay мы собираемся зарегистрировать и

// показать миру. Он, как и положено, происходит от

// IUnknown и содержит чисто виртуальные функции

interface ISay : public lUnknown

{

//=== 2 метода, которые интерфейс

//=== предоставляет своим клиентам

virtual HRESULT _stdcall Say 0=0;

virtual HRESULT _stdcall SetWord (BSTR word)=0;

}

#endif

Абстрактный интерфейс не может жить сам по себе. Он должен иметь класс-оболочку (wrapper class), который на деле реализует виртуальные методы Say и SetWord. Этот так называемый ко-класс (класс СОМ-компонента) производится от интерфейса ISay и предоставляет тела всем унаследованным (чисто) виртуальным методам своего родителя. Так как у интерфейса ISay, в свою очередь, имеется родитель (lUnknown), то класс должен также дать реальные тела всем трем методам IUnknown.

Примечание 2
Примечание 2



Если вы хотите, чтобы класс реализовывал несколько интерфейсов, то вы должны использовать множественное наследование. Такой подход проповедует ATL (Active Template Library). MFC реализует другой подход к реализации интерфейсов. Он использует вложенные классы. Каждому интерфейсу соответствует новый класс, вложенный в один общий класс СОМ-объекта.

Для того чтобы быть доступным тем приложениям, которые захотят воспользоваться услугами СОМ-объекта, сам класс тоже должен иметь дом (в виде inproc-сервера DLL). Сейчас, разрабатывая проект типа Win32 DLL, мы строим именно этот дом. С помощью механизма DLL класс будет доступен приложению-клиенту, в адресное пространство процесса которого он загружается. Вы знаете, что DLL загружается в пространство клиента только при необходимости.

Нам неоднократно понадобятся услуги инструмента Studio.Net под именем GuidGen, поэтому целесообразно ввести в меню Tools (Инструментальные средства) Studio.Net новую команду для его запуска. GuidGen, так же как и UuidGen, умеет генерировать уникальные 128-битовые идентификаторы, но при этом он использует удобный Windows-интерфейс. А идентификаторы понадобятся нам для регистрации сервера и класса CoSay. Для введения новой команды:

  1. Дайте команду Tools > External Tools и в окне диалога External Tools нажмите кнопку Add.
  2. Введите имя новой команды меню GuidGen, переведите фокус в поле Command и нажмите кнопку справа от нее.
  3. С помощью диалога поиска файла, найдите файл Guidgen.exe, который находится в папке .. .\Microsoft Visual Studio.Net\Common7\Tools, и нажмите кнопку Open.
  4. Переведите фокус в поле Initial Directory и с помощью кнопки раскрытия выпадающего списка выберите элемент Item Directory.
  5. Нажмите OK и теперь с помощью новой команды GuidGen меню Tools вызовите генератор уникальных идентификаторов.
  6. Выберите формат DEFINE_GUID и нажмите кнопку Сору, а затем Exit.
  7. В окне редактора Studio.Net поместите фокус перед строкой interface ISay и нажмите Ctrl+C. При этом из системного буфера в файл будут помещены три строки кода, которые с точностью до цифр, которые у вас будут другими, имеют такой вид:
// {170368DO-85BE-43af-AE71-053F506657A2}

DEFINE_GUID («name»,

0xl70368d0, 0x85be, 0x43af, 0xae, 0x71, 0x5, Ox3f, 0x50,

0x66, 0x57, Oxa2);

Замените аргумент «name» на HD_ISay. Повторите всю процедуру и создайте идентификатор для ко-класса CoSay, который вставьте сразу за идентификатором интерфейса ISay. На сей раз замените аргумент «name» на CLSiD_CoSay, например:

// {9B865820-2FFA-lld5-98B4-OOE0293F01B2}

DEFINE_GUID(CLSID_CoSay,

0х9b865820, 0x2ffa, 0xlldS, 0x98, 0xb4, 0x0, 0xe0, 0x29,

0x3f, 0xl, 0xb2);

Сохраните и закройте файл interfaces.h, так как мы больше не будем вносить в него изменений. Если вы хотите знать, что делает макроподстановка DEFINE_GUID, то за ней стоит такое определение:

#define DEFINE_GUID

(name, 1, wl, w2, \ b1, b2, bЗ, b4, b5, b6, b7, b8) \ EXTERN_C

const GUID name \

= { 1, wl, w2, { b1, b2, bЗ,b4, b5, b6, b7, b8 } }

Оно означает, что макрос создает структуру с именем <name> типа GUID, которая служит для хранения уникальных идентификаторов СОМ-объектов, интерфейсов, библиотек типов и других реалий причудливого мира СОМ.



Содержание раздела