Глава 23. СОМ и ATL

В предыдущих двух главах говорилось о том, что технологии OLE и ActiveX основаны на модели компонентных объектов — СОМ. Как вы помните, СОМ определяет механизмы предоставления объектом своих свойств и методов, а также принципы межзадачного взаимодействия объектов и контейнеров. В этой главе вы познакомитесь с библиотекой активных шаблонов — ATL (ActiveTemplateLibrary), с помощью которой можно легко создавать СОМ-объекты, элементы управления ActiveXи многое другое. ATLтакже содержит встроенные средства поддержки большинства базовых интерфейсов СОМ.

Мы создадим простое ATL-приложение, в котором будут совмещены возможности сгенерированного шаблонного проекта Polygonи элемента управления ActiveX, разработанного нами в предыдущей главе. Затем мы встроим полученный СОМ-объект в HTML-документ, который можно просматривать с помощью броузера InternetExplorer.

Создание ATL-проекта Polygon

ATL-проекты создаются с помощью мастера ATLCOMAppWizard. Делается это следующим образом.

1.    В окне компилятора VisualC++ в меню Fileвыберите команду Newи в открыв­шемся диалоговом окне перейдите на вкладку Projects.

2.   Выберите элемент ATLCOMAppWizard.

3.    В качестве имени проекта введите Polygon(рис. 23.1).

После щелчка на кнопке ОК откроется окно мастера ATLCOMAppWizard(рис. 23.2).


Рис. 23.1. Выбор типа проекта


Рис. 23.2. Окно мастера ATL-проекта

В группе опций ServerType установите переключатель DynamicLinkLibrary (DLL) и щелкните на кнопке Finish. Откроется окно NewProjectInformation с итоговой информацией о создаваемом ATL-проекте (рис. 23.3).


Рис. 23.3. Диалоговое окно New Project Information

Щелкните на кнопке ОК, чтобы запустить процесс генерирования кода программы.

Пока что мастер создал лишь оболочку проекта, в которую необходимо добавить один или несколько элементов управления. Это можно сделать с помощью мастера ATL-объектов, который вызывается по команде NewATLObject... из меню Insert(рис. 23.4).


Рис. 23.4. Мастер ATL Object Wizard позволяет добавлять в ATL-проект различные элементы управления

В окне мастера в списке Category выберите элемент Controls, затем в списке Objects— элемент FullControl и щелкните на кнопке Next. В открывшемся диалоговом окне вам представится возможность задать различные параметры конфигурации создаваемого элемента управления. Сначала на вкладке Names в поле ShortName введите имя объекта — Polyctl. Все остальные поля будут автоматически инициализированы самим мастером (рис. 23.5).


Рис. 23.5. В окне свойств можно установить характеристики элеменета управления

Теперь перейдите на вкладку Attributes и установите опции Support ISupportErrorInfo и Support Connection Points (рис. 23.6).


Рис. 23.6. На вкладке Attributes устанавливаются служебные опции

Далее активизируйте вкладку StockProperties и выберите свойство FillColor, которое будет поддерживаться элементом управления (рис. 23.7).

Щелкните на кнопке ОК, после чего мастер добавит в проект код элемента управления.

Процесс завершен, и теперь в меню Build можно выбрать команду Build или RebuildAll для компиляции проекта. По окончании компиляции задайте в меню Tools команду ActiveXControlTestContainer, чтобы протестировать созданный элемент управления.


Рис. 23.7. На вкладке Stock Properties выбираются базовые свойства, подддерживаемые элементом управления

В окне контейнера в меню Edit выберите команду InsertNewControl, в открывшемся диалоговом окне InsertControl найдите класс PolyCtl, после чего нажмите кнопку ОК.

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

Модификация шаблона

Далее необходимо внести некоторые изменения в сгенерированный мастером ATLCOMAppWizard шаблон проекта Polygon.

Добавление свойства

Свойства элемента управления реализуются посредством интерфейса iPolyCtl. Чтобы добавить новое свойство, в окне компилятора VisualC++ перейдите на вкладку ClassView, выберите интерфейс IPolyCtl и щелкните правой кнопкой мыши, после чего в открывшемся контекстном меню выберите команду AddProperty.... На экране появится диалоговое окно AddPropertytoInterface(рис. 23.9).


Рис. 23.9. В окне Add to Property to Interface можно добавить к элементу управления новое свойство

Из списка PropertyType выберите тип данных short, затем в поле PropertyName введите имя свойства Sides и щелкните на кнопке ОК. Компилятор MIDL(программа, которая создает файлы с расширением IDL) сгенерирует методы get_Sides()и put_sides(),управляющие получением и установкой значения данного свойства. Прототипы этих функций добавляются в файл POLYCTL.H, а их базовые реализации — в файл POLYCTL.CPP. Мы к ним еще вернемся.

Реализация точек подключения

Для нашего проекта также необходим интерфейс точек подключения (connectionpoints), формирующий канал передачи сообщений между элементом управления и его контейнером. СОМ-объект может иметь несколько точек подключения и, кроме того, должен реализовывать интерфейс контейнера точек подключения — iConnectionPointContainer.

Прежде всего нам нужно добавить к интерфейсу диспетчеризации событий _IPolyCtlEventsдва метода — clickin() и ClickOut(), которые сигнализируют о том, что щелчок мышью выполнен соответственно внутри и вне многоугольника, рисуемого в элементе управления. Перейдите на вкладку ClassView, щелкните правой кнопкой мыши на элементе _IPolyCtlEventsи выберите из контекстного меню команду AddMethod. В открывшемся диалоговом окне AddMethodtoInterface в списке ReturnType укажите тип возвращаемого значения void, в поле MethodName введите имя метода Clickin, а в поле Parameters задайте описание входных параметров х и у, как показано на рис. 23.10. Повторите эту процедуру для метода ClickOut.

Строки с описанием данных методов будут добавлены в файл POLYGON. IDL— библиотеку типов элемента управления. Прежде чем переходить к следующему шагу, скомпилируйте библиотеку типов, щелкнув на имени указанного файла на вкладке FileView и выбрав в контекстном меню команду CompilePOLYGON.IDL.

Далее на вкладке ClassViewщелкните правой кнопкой мыши на элементе CPolyCtl и выберите из контекстного меню команду ImplementConnectionPoint. В открывшемся одноименном диалоговом окне (рис. 23.11) должна содержаться единственная вкладка POLYGONLib(это название библиотеки типов элемента управления). В списке Interfaces перечисляются интерфейсы диспетчеризации, описанные в данной библиотеке. В нашем случае такой интерфейс один: _lPolyCtlEvents. В поле Filename указано имя файла (POLYGONCP.H), в который будет помещен специальный код, управляющий транспортировкой сообщений между элементом управления и контейнером. Поставьте метку напротив интерфейса_IPolyCtlEventsи нажмите кнопку ОК


Рис. 23.10. Окно Add Method to Interface


Рис. 23.11. Окно Implement Connection Point

В результате выполненных действий будет создан файл POLYGONCP.H, содержащий реализацию класса CProxy_iPolyCtlEvents, потомка класса iConnectionPointlmpl, и двух его методов, Fire_ClickIn() и Fire_ClickOut(), управляющих вызовом упоминавшихся ранее методов ClickIn() и ClickOut().В файле POLYCTL.H в список предков класса CPolyCtl будет добавлен класс CProxy_iPolyCtlEvents, а в схему СОМ-интерфейсов будет помещена запись

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)

Кроме того, будет обновлена схема точек подключения класса CPolyCtl:

BEGIN_CONNECTION_POINT_MAP(CPolyCtl)

CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
CONNECTION_POINT_ENTRY(DIID_I PolyCtlEvents)

END_CONNECTION_POINT_MAP()

Добавление обработчика сообщения

Обработчик сообщения wm_lbuttondown необходим для определения момента, когда пользователь щелкает левой кнопкой мыши на элементе управления. Перейдите на вкладку ClassView, щелкните правой кнопкой мыши на элементе CPolyCtl и выберите из контекстного меню команду AddWindowsMessageHandler. В открывшемся диалоговом окне в левом списке выберите сообщение wm_lbuttondown, щелкните на кнопке AddHandler и нажмите кнопку ОК.

В результате в файл POLYCTL.H будет добавлена стандартная реализация метода OnLButtonDown(), а в схеме сообщений класса CPolyCtl появится новая запись:

BEGIN_MSG_MAP(CPolyCtl)

CHAIN_MSG_MAP(CComControl<CPolyCtl>)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_LB0TTONDOWN, OnLButtonDown)

END MSG MAP()

Внесение изменений в файл POLYCTL.H

Следующим шагом будет внесение некоторых изменений в файл POLYCTL.H, текст которого показан ниже. Дополнения и изменения выделены полужирным шрифтом.

// PolyCtl.h: Объявление класса CPolyCtl

#ifndef _POLYCTL_H_

#define _POLYCTL_H_

#include <math.h>

#include "resource.h"  // основные константы
#include <atlctl.h>
#include "PolygonCP.h"

/////////////////////////////////////////

11 CPolyCtl

class ATL_NO_VTABLE CPolyCtl :

public CComObjectRootEx<CComSingleThreadModel>,

public CStockPropImpKCPolyCtl, IPolyCtl, SIID_IPolyCtl, SLIBID_POLYGONLib>,

public CComControl<CPolyCtl>,

public IPersistStreamInitImpl<CPolyCtl>,

public I01eControlImpl<CPolyCtl>,

public I01eObjectImpl<CPolyCtl>,

public I01eInPlaceActiveObjectImpl<CPolyCtl>,

public IViewObjectExImpKCPolyCtl>,

public I01eInPlaceObjectWindowlessImpl<CPolyCtl>,

public ISupportErrorlnfo,

public IConnectionPointContainerImpl<CPolyCtl>,

public IPersistStorageImpl<CPolyCtl>,

public ISpecifyPropertyPagesImpl<CPolyCtl>,

public IQuickActivateImpl<CPolyCtl>,

public IDataObjectImpl<CPolyCtl>,

public IProvideClassInfo2Impl<SCLSID_PolyCtl, SDIID_IPolyCtlEvents,

&LIBID_POLYGONLib>,

public IPropertyNotifySinkCP<CPolyCtl>,

public CComCoClass<CPolyCtl, SCLSID_Po.lyCtl>

public CProxy_IPolyCtlEvents< CPolyCtl > { public:

CPolyCtl ()

{

m_nSides =6;      // по умолчанию строится шестиугольник
m_clrFillColor = RGB(OxFF, OxFF, 0); // желтый цвет заливки

}

DECLARE_REGISTRY_RESOURCEID(IDR_POLYCTL) DECLARE PROTECT FINAL CONSTRUCT))

BEGIN_COM_MAP(CPolyCtl)

COM_INTERFACE_ENTRY(IPolyCtl)

COM_INTERFAOE_ENTRY(IDispatch)

COM_INTERFACE_ENTRY(IViewObjectEx)

COM_INTERFACE_ENTRY(IViewObject2)

COM_INTERFACE_ENTRY(IViewObject)

COM_INTERFACE_ENTRY(IDlelnPlaceObjectWindowless)

COM_INTERFACE_ENTRY(I01eInPlaceObject)

COM_INTERFACE_ENTRY2(IQleWindow, IQlelnPlaceObjectWindowless)

COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)

COM_INTERFACE_ENTRY(I01eControl)

COM_INTERFACE_ENTRY(IQleObject)

COM_INTERFACE_ENTRY(IPersistStreamlnit)

COM_INTERFACE_ENTRY2(IPersist, IPersistStreamlnit)

COM_INTERFACE_ENTRY(ISupportErroriInfo)

COM_INTERFACE_ENTRY(IConnectionPointContainer)

COM_INTERFACE_ENTRY(ISpecifyPropertyPages)

COM_INTERFACE_ENTRY(IQuickActivate)

COM_INTERFACE_ENTRY(IPersistStorage)

COM_INTERFACE_ENTRY(IDataObject)

COM_INTERFACE_ENTRY(IProvideClassInfo)

COM_INTERFACE_ENTRY(IProvideClassInfo2)

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)     ^ END_COM_MAP()

BEGIN_PROP_MAP(CPolyCtl)

PROP_DATA_ENTRY("_cx",m_sizeExtent.ex, VT_UI4) PROP_DATA_ENTRY("_Gy",m_sizeExtent.cy, VT_UI4) PROP_ENTRY("FillColor",DISPID_FILLCOLOR, CLSID_StockColorPage)

END_PROP_MAPt)

BEGIN_CONNECTION_POINT_MAP(CPolyCtl)

CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink) CONNECTION_POINT_ENTRY(DIID_IPolyCtlEvents)

END_CONNECTION_POINT_MAP ()

BEGIN_MSG_MAP(CPolyCtl)

CHAIN_MSG_MAP(CComControl<CPolyCtl>)

DEFAULT_REFLECTION_HANDLER() END_MSG_MAP ()

// ISupportErrorlnfo

STDMETHOD(InterfaceSupportsErrorInfo) (REFIID riid)

{

static const IID* arr[]=

{

&IID_IPolyCtl,

{

for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)

{

if (InlineIsEqualGDID(*arr[i], riid))

return S_OK; } return S_FALSE;

}.

// IViewObjectEx

DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATOS_OPAQUE)

// IPolyCtl public:

STDMETHOD(get_Sides)(/*[out,retval]*/ short *pVal);

STDMETHOD(put_Sides) </*[in]*/short newVal);

HRESULT OnDraw(ATL_DRAWINFOS di);

LRESULT OnLButtonDown(UINT uMsg,
WPARAM wParam, LPARAM IParam, BOOLS bHandled)

OLE_COLOR m_clrFillColor;
short m_nSides; POINT m_arrPoint[10];

};

#endif // _ POLYCTL_H_

В конструкторе класса CPolyCtlустанавливается, что по умолчанию число сторон многоугольника, рисуемого в элементе управления, равно шести (минимальное — 3, максимальное — 10), а для заливки используется желтый цвет. Для вычисления координат вершин многоугольника потребуются тригонометрические функции, поэтому в проект включается библиотека МАТН.Н.

Стандартные реализации функций OnDraw( ) и OnLButtonDown( ) были удалены из файла, так как мы значительно расширим их и включим в файл POLYCTL.CPP.

Реализация методов элемента управления

Ниже приведен текст файла POLYCTL.CPP. Все дополнения и изменения выделены полужирным шрифтом.

// PolyCtl.cpp: Реализация класса CPolyCtl

#include "stdafx.h"

#include "Polygon. h"

#include "PolyCtl.h"

#include <time.h>
#include <string.h>

////////////////////////////////

// CPolyCtl

HRESULT CPolyCtl: : OnDraw (ATL_DRAHINFO& di)

{

struct tm *date_time;

time_t timer;

static TEXTMETRIC tin;

RECTS rc = *(RECT*)di.prcBounds; HDC hdc = di.hdcDraw;

COLORREF colFore;

HBRUSH hOldBrush, hBrush;

HPEN hOldPen, hPen;

// Приведение переменной m_clrFillColor к типу COLORREF
OleTranslateColor(m_clrFillColor, NULL, ScolFore);

// Выбор пера и кисти для рисования окружности
hPen - (HPEN)GetStockObject(BLACK_PEN);
hOldPen = (HPEN)SelectObject (hdc, hPen);
hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);

const double pi = 3.14159265358979; POINT ptCenter;

double dblRadiusx = (rc.right - rc.left) / 2;
double dblRadiusy = (rc.bottom - rc.top) / 2;
double dblAngle = 3 * pi / 2;
double dblDiff = 2 * pi / m_nSides;
ptCenter.x = (rc.left + rc.right) / 2;
ptCenter.у = (rc.top + rc.bottom) / 2;

// Вычисление координат вершин
for (int i = 0; i < m_nSides; i++) {

m arrPoint[i].x = (long) \

(dblRadiusx*cos(dblAngle)+ptCenter.x+0.5);

m_arrPoint[i].y = (long) \

(dblRadiusy*sin (dblAngle) -1-ptCenter. y+0.5) ;

dblAngle += dblDiff; } Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);

// Создание и выбор кисти для заливки многоугольника
hBrush = CreateSolidBrush(colFore);
SelectObject(hdc, hBrush);
Polygon(hdc, Sm_arrPoint[0], m_nSides);

// Вывод даты и времени

time(Stimer);

date_time = localtime(<<timer);

const char* strtime;

strtime = asctime(date_time);

SetBkMode(hdc, TRANSPARENT);

SetTextAlign(hdc, TA_CENTER | TA_TOP); ExtTextOut(hdc, (rc.left + rc.right)/2,

(rc.top + rc.bottom - tan.tmHeight)/2,

ETO_CLIPPED, Src, strtime, strlen (strtime) -1,NULL);

// Восстановление старых пера и кисти
SelectObject(hdc, hOldPen) ;
SelectObject(hdc, hOldBrush) ;
DeleteOb ject (hBrush) ;

return S_OK;

LRESULt CPolyCtl: : OnLButtonDown (UINT uMsg, WPJUWM wParam,

LPARAM 1 Par am, BOOLS bHandled)

{

HRGNhRgn;

WORDxPos= LOWORD(lParam) ;  // положение указателя по горизонтали

WORDyPos= HIWORD(lParam) ;  // положение указателя по вертикали

// Создание многоугольника по списку координат вершин

hRgn = CreatePolygonRgn(sm_arrPoint[0] , m_nSides, WINDING);

// Если точка щелчка попадает внутрь многоугольника,

// то генерируется событие Clickln,

// в противном случае - событие ClickOut

if (PtInRegion(hRgn, xPos, yPos) )

Fire_ClickIn (xPos , yPos) ; else

Fire_ClickOut (xPos , yPos) ;

// Освобождение дескриптора
DeleteOb ject (hRgn) ;
return 0 ;

}

STDMETHODIMP CPolyCtl::get_Sides(short *pVal) (

*pVal = m_nSides;

return S_OK; }

STDMETHODIMP CPolyCtl::put_Sides(short newVal)

{

if (newVal > 2 ££ newVal < 11) {

m_nSides = newVal;

FiifeViewChangeO ;

return S_OK; ) else

return Error(_T("Must have between 3 and 10 sides"));

}

Отображаемые дата и время будут обновляться каждый раз после выполнения щелчка на элементе управления. Метод put_Sides() изменен таким образом, чтобы вызывать функцию FireViewChange(), которая, в свою очередь, вызывает функцию invalidateRect(), обозначающую область перерисовки элемента управления как недействительную. Если этого не сделать, изображение элемента управления не будет обновляться после щелчка на нем мышью.

Добавление страницы свойств

С помощью того же мастера ATL-объектов можно добавить в элемент управления страницу свойств. Для этого выберите в меню Insert командуNew ATL Object... (рис. 23.13).


Рис. 23.13. С помощью мастера ATL Object Wizard можно добавить в проект страницу свойств

Выделите категорию Controls, в ней — элемент PropertyPageи щелкните на кнопке Next. В следующем окне мастера можно установить параметры, определяю­щие работу страницы свойств. На вкладке Namesв поле ShortNameвведите имя объекта — PolyProp. Все остальные поля будут заполнены мастером автоматически (рис. 23.14).


Рис. 23.14. Задание параметров создаваемой страницы свойств

Теперь перейдите на вкладку Strings и заполните поля Title(текст ярлычка вкладки) и DocString(строка описания), а поле Helpfile (ассоциированный файл справки) очистите (рис. 23.15).


Рис. 23.15. На вкладке Strings следует заполнить поля Title и Doc String

После щелчка на кнопке ОК будут созданы новые файлы POLYPROP.H, POLYPROP.CPPи POLYPROP.RGS. Далее необходимо изменить внешний вид страницы свойств. Откройте с помощью вкладки ResourceViewдиалоговое окно с идентификатором lDD_PObYPROp, поменяйте существующую надпись на Sides: и добавьте текстовое поле с идентификатором IDC_SIDEs(рис. 23.16).


Рис. 23.16. Изменение внешнего вида страницы свойств

Теперь нужно добавить обработчик, управляющий изменением значения поля idc_sides. Для этого выполните щелчок правой кнопкой мыши на поле и выберите в контекстном меню команду Events. В появившемся окне выберите в списке Classorobjecttohandle элемент IDC_SIDBS, а затем в списке NewWindowsMessages/Events— сообщение EN_CHANGE. Щелкните на кнопке AddHandler, после чего в открывшемся окне AddMemberFunctionбудет предложено имя обработчика (рис. 23.17).


Рис. 23.17. Добавление обработчика сообщений

Примите предлагаемое имя OnChangeSides и закройте оба окна. В результате в файл POLYPROP.H будет добавлена стандартная реализация данного обработчика, а в схеме сообщений класса CPolyProp появится новая запись:

BEGIN_MSG_MAP(CPolyProp)

CHAIN_MSG_MAP(IPropertyPageImpKCPolyProp>)
COMMAND_HANDLER(IDC_SIDES,   EN_CHANGE,   OnChangeSides)

END_MSG_MAP ()

Следующим шагом будет внесение изменений в файл POLYPROP.H:

// PolyProp.h: Объявление класса CPolyProp

#ifndef _POLYPROP_H_

#define _POLYPROP_H_

#include "resource.h"      // основные константы
#include "Polygon.h"

EXTERN_C const CLSID CLSID_PolyProp;

///////////////////////////////////////////////

II CPolyProp

class ATL_NO_VTABLE CPolyProp :

public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CPolyProp, &CLSID_PolyProp>,
public IPropertyPageImpl<CPolyProp>,
public CDialogImpl<CPolyProp> { public:

CPolyProp ( ) {

m_dwTitleID = IDSJTITLEPolyProp; m_dwHelpFileID - IDS_HELPFILEPolyProp; m_dwDocStringID = IDS_DOCSTRINGPolyProp;

}

enura (IDD = IDD_POLYPROP};

DECLARE_REGISTRY_RESOURCEID ( IDR_POLYPROP) DECLARE_PROTECT_FINAL_CONSTRUCT ( )

BEGIN_COM_MAP (CPolyProp)             -

COM_INTERFACE_ENTRY ( I Proper tyPage ) END_COM_MAP ( )

BEGIN_MSG_MAP (CPolyProp)

CHAIN_MSG_MAP ( IPropertyPageImpKCPolyProp>) COMMAND_HANDLER(IDC_SIDES, EN_CHANGE, OnChangeSides)

END_MSG_MAP ( )

STDMETHOD (Apply) (void) 1

OSES_CONVERSION ;

ATLTRACE (_T ( "CPolyProp: :Apply\n") ) ;

for (UINT i = 0; i < m_nObjects; i++)

{

CComQIPtr<IPolyCtl , SIID_IPolyCtl> pPoly (m_ppOnk[i]) ;
short nSides = ( short) GetDlgl temlnt (IDC_SIDES) ;
if FAILED (pPoly->put_Sides (nSides) ) {

CComPtr<IErrorInf o> pError ; CComBSTR     strError;
GetErrorInfo(0, SpError) ;
pError->GetDescription (fistrError) ;
MessageBox(OLE2T(strError) , _T ("Error"),

MB_ICONEXCLAMATION) ;
return E_FAIL; } } m_bDirty = FALSE;

return S_OK; }
LRESULT OnChangeSides(WORD wNotifyCode, WORD wID,

HWND hWndCtl, BOOL& bHandled) {

SetDirty(TRCE);
return 0;
}
}; 

#endif //_POLYPROP_H_

Страница свойств может быть вызвана сразу несколькими клиентами. Для обслуживания всех клиентов в функции Apply() запускается цикл и в нем вызывается метод put_Sides() для каждого клиента, данные которого были введены в текстовое поле.

Страница свойств добавляется в проект с помощью единственной строки в файле POLYCTL.H: 

BEGIN_PROP_MAP(CPolyCtl)

PROP_DATA_ENTRY("_c.x", m_sizeExtent.ex, VT_UI4)

PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)

PROPJ3NTRY("FillColor", DISPID_FILLCOLOR, CLSID_StockColorPage)

PRQP_ENTRY("Sides", 1, CLSID_PolyProp) END_PROP_MAP 0

Теперь можно приступать к тестированию элемента управления на Web-странице.

Тестирование элемента управления ATLна Web-странице

Мастер ATL-объектов создает исходный элемент управления вместе с тестовым HTML-файлом, который находится в папке проекта. Он называется POLYCTL.HTM и может быть открыт в броузере Microsoft Internet Explorer. С помощью данного файла можно протестировать созданный нами элемент управления. Но прежде в этот файл следует внести изменения, выделенные ниже полужирным шрифтом:

<HTML>

<HEAD>

<TITLE>ATL 3.0 test page for object PolyCtl</TITLE>

</HEAD>

<BODY>

<OBJECT ID="PolyCtl"

CLASSID="CLSID:4CBBC676-507F-11DO-B98B-000000000000"> </OBJECT>

<SCRIPT LM>>GOAGE="VBScript"> <! —

Sub PolyCtl_ClickIn(x, y)

PolyCtl.Sides = PolyCtl.Sides + 1

End Sub

Sub PolyCtl_ClickOut(x, у)

PolyCtl.Sides = PolyCtl.Sides - 1

End Sub —>

</SCRIPT>

</BODY>
</HTML>

Теперь запустите Internet Explorer и откройте в нем файл POLYCTL.HTM. Начальное содержимое Web-страницы показано на рис. 23.18.

Выполните несколько щелчков мышью внутри и вне многоугольника. Как вы убедитесь, число вершин станет автоматически увеличиваться >> уменьшаться, если только не будут достигнуты граничные значения 2 и 11 — в этом случае выдается сообщение об ошибке Must have between 3 and 10 sides. На рис. 23.19 показано, как изменится внешний вид элемента управления после двух щелчков внутри многоугольника.


Рис. 23.18. Исходный вид созданного вами элемента управления ATL

Примечание

Убедитесь, что в свойствах Internet Explorer установлен низкий уровень безопасности. По умолчанию задается средний уровень, но в этом случае выполнение сценариев неподписанных элементов управления ActiveX запрещено.


Рис. 23.19. Вид элемента управления после двух последовательных щелчков на нем