Класс-оболочка
Обычно при
создании приложения-контейнера для элемента ActiveX придерживаются следующей
стратегии:
- Вставляют уже зарегистрированный
элемент ActiveX в форму приложения контейнера, используя так называемую галерею
объектов (Gallery).
- В одном из классов контейнера
определяют переменную того же типа, что и класс-оболочка для внедренного элемента.
- Программируют поведение
элемента, управляя им с помощью этой переменной.
Первый шаг
этого алгоритма вы уже выполнили, теперь введите в состав проекта два новых
файла OpenGLh и OpenGLcpp, которые будут содержать коды класса-оболочки copenGL.
Вот содержимое файла заголовков (OpenGLh):
#pragma
once
//===========
COpenGL wrapper class
class
COpenGL :
public CWnd
{
protected:
DECLARE_DYNCREATE(COpenGL)
public:
//====
Метод для добывания CLSID нашего элемента
CLSID
const& GetClsidO
{
static
CLSID
const clsid =
{
0x519d9ed8,
Oxbc4'6, 0x4367,
{
Ox9c, OxcO, 0x49, 0x81, 0x40, Oxf3, 0x94, 0x16 }
};
return
clsid;
}
virtual
BOOL Create(LPCTSTR IpszClassName,
LPCTSTR
IpszWindowName, DWORD dwStyle,
const
RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL)
{
return
CreateControl(GetClsid(), IpszWindowName,
dwStyle,
rect, pParentWnd, nID)
}
BOOL
Create (LPCTSTR IpszWindowName, DWORD dwStyle,
const
RECT& rect, CWnd* pParentWnd, UINT nID, CFile* pPersist = NULL,
BOOL
bStorage = FALSE, BSTR bstrLicKey = NULL)
{
return
CreateControl(GetClsidO, IpszWindowName, dwStyle, rect, pParentWnd, nID,
pPersist, bStorage, bstrLicKey);
}
//======
Методы, экспонируемые элементом ActiveX
public:
void
SetFillColor(unsigned long newValue);
unsigned
long GetFillColor();
void
GetLightParams(long* pPos);
void
SetLightParam(short Ip,
long nPos);
void
ReadData();
void
SetFillMode(DWORD mode);
void
GetFillMode(DWORD* pMode);
void
GetQuad(BOOL* bQuad);
void
SetQuad(BOOL bQuad);
};
Самым важным
моментом в процедуре вставки класса является правильное задание CLSID того класса
OpenGL, который был зарегистрирован в операционной системе при создании DLL-сервера,
то есть нашего элемента ActiveX. He пытайтесь сравнивать те цифры, которые приведены
в книге, с теми, которые были приведены в ней же до этого момента, так как в
процессе отладки пришлось не раз менять как классы, так и целиком приложения.
Мне не хочется отслеживать эти жуткие номера. Если вы хотите вставить правильные
цифры, то должны взять их из вашей версии предыдущего приложения ATLGL.
Например, откройте файл ATLGL.IDL и возьмите оттуда CLSID для ко-класса OpenGL,
то есть найдите такой фрагмент этого файла:
[
uuid(519D9ED8-BC46-4367-9CCO-498140F39416),
helpstring("OpenGL
Class") ]
coclass
OpenGL
{
[default]
interface IOpenGL;
[default,
source] dispinterface _IOpenGLEvents;
};
И скопируйте
первую строку
uuid(519D9ED8-BC46-4367-9CCO-498140F39416),
но с вашими
цифрами и вставьте ее в качестве комментария в файл OpenGLh нового
проекта TestGL. Затем аккуратно, соблюдая формат, принятый для структуры CLSID,
перенесите только цифры в поля статической структуры clsid, которую вы видите
в методе GetClsid класса-оболочки. Цифры должны быть взяты из принесенной строки,
но их надо отформатировать (разбить) по-другому принципу. Например, для нашего
случая правильным будет такое тело метода GetClsid:
CLSID
const& GetClsid()
{
//
Следующая строка взята из файла ATLGL.IDL
//
519D9ED8-BC46-4367-9CCO-498140F39416
static
CLSID
const clsid =
{
//========
Эти цифры взяты из файла ATLGL.IDL
0x519d9ed8,
0xbc46, 0x4367,
{
0х9с, 0xc0, 0x49, 0x81, 0x40, 0xf3, 0x94, 0x16 } ) ;
return
clsid;
}
Кроме этого
важного фрагмента в новом классе объявлены два совмещенных метода Create, каждый
из которых умеет создавать окно внедренного элемента ActiveX с учетом особенностей
стиля окна (см. справку по CWnd: :CreateControl). Затем в классе-оболочке должны
быть представлены суррогаты всех методов, экспонируемых классом OpenGL COM DLL-сервера
ATLGL.DLL. В том, что вы не полностью приводите тела методов сервера, иначе
это был бы абсурд, хотя и так близко к этому, можно убедиться, просмотрев на
редкость унылые коды реализации класса-оболочки, которые необходимо вставить
в файл OpenGLcpp. Утешает мысль, что в исправной Studio.Net эти коды не придется
создавать и редактировать вручную:
#include
"stdafx.h"
#include
"opengl.h"
IMPLEMENT_DYNCREATE(COpenGL,
CWnd)
//======
Стандартное свойство реализовано
//======
в виде пары методов Get/Set
void
COpenGL::SetFillColor(unsigned
long newValue)
{
static
BYTE parms[] =
VTS_I4;
InvokeHelper(0xfffffe02, DISPATCH_PROPERTYPUT,VT_EMPTY,
NULL,
parms, newValue);
}
//======
Стандартное свойство
unsigned
long COpenGL::GetFillColor0 {
unsigned
long result;
InvokeHelper
(Oxfffffe02, DISPATCH_PROPERTYGET, VT_I4,
(void4)&result,
NULL);
return
result;
}
//======
Наши методы сервера
void
COpenGL::GetLightParams(long* pPos)
{
static
BYTE parms[] = VTS_PI4;
InvokeHelper
(Oxl, DISPATCH_METHOD, VT_EMPTY, NULL,
parms,
pPos);
}
void
COpenGL: : SetLightParam (short lp, long nPos)
{
static
BYTE parms [ ] = VTS 12 VTS 14;
InvokeHelper{0x2,
DISPATCH_METHOD, VT_EMPTY, NULL,
parms,
lp, nPos);
}
void
COpenGL::ReadData()
InvokeHelper(0x3,
DISPATCH_METHOD, VT_EMPTY, 0, 0) ;
void
COpenGL::GetFillMode(DWORD* pMode)
static
BYTE jparms[] =
VTS_PI4;
InvokeHelper (0x4, DISPATCH_METHOD, VT_EMPTY, NULL,
parms,
pMode);
}
void
COpenGL::SetFillMode(DWORD nMode)
static
BYTE parms[] =
VTS_I4;
InvokeHelper(0x5,
DISPATCH_METHOD, VT_EMPTY, NULL, parms, nMode);
void
COpenGL::GetQuad(BOOL* bQuad)
static
BYTE parms[] =
VTS_PI4;
InvokeHelper(0x6,
DISPATCH_METHOD, VT_EMPTY, NULL, parms, bQuad);
void
COpenGL::SetQuad(BOOL bQuad)
static
BYTE parms[] =
VTS_I4;
InvokeHelper
(0x7, DISPATCH_METHOD, VT_EMPTY, NULL, parms, bQuad);
}
Затем подключите
оба новых файла к проекту Project > Add Existing Item.