目录
ATL7.1编写ActiveX控件... 1
目录... 1
一创建ATL项目... 1
二创建ActiveX控件... 2
三解释向导的行为... 3
四标准属性... 4
背景属性... 4
五 Unicode风格编码... 11
六用OpenGL绘制笛卡尔坐标系... 11
七自定义属性... 15
八自定义方法... 17
九标准方法... 17
十标准事件... 18
十一自定义事件... 18
一 创建ATL项目
我们创建dll形式的ATL项目EllipseCase 如下图:
二 创建ActiveX控件
我打算创建一个Ellipse控件,该控件拥有背景属性,可以改变背景颜色。
该控件绘制一个笛卡尔坐标系,用户可以通过右键菜单修改X、Y、Z轴的颜色。
好啦,现就这么多了,让我上路吧。
重要提醒:如果你要创建一个能够处理WM_CREATE消息的ActiveX控件,请注意:
必须------
a)       选择标准控件
b)      选中仅适用于有窗口的
c)      在构造函数中加上m_bWindowOnly=TRUE。
其中的原因在于符合控件派生自CComCompositeControl<>模板类,而标准控件派生自CComControl<>类。派生自CComCompositeControl类意味着该类可以包容其它的控件,但是同时具有了对话框的特征,且拥有了自己的对话框资源。所以如果想要添加初始化代码,应该处理WM_INITDIALOG消息。如果我们想在自己的控件中包含另一个ActiveX控件,我们应该创建复合控件,并用对话框承载想要包含的ActiveX控件。
三 解释向导的行为
我们先停下来,了解一下ActiveX控件的基础知识,并理解向导生成的代码。
看看CEllispe的父类
classATL_NO_VTABLE CEllispe :
public CComObjectRootEx<CComSingleThreadModel>,
publicCComCoClass<CEllispe, &CLSID_Ellispe>,
publicIPersistStreamInitImpl<CEllispe>,
publicISpecifyPropertyPagesImpl<CEllispe>,
publicIPersistStorageImpl<CEllispe>,
public CStockPropImpl<CEllispe, IEllispe>,
public IOleControlImpl<CEllispe>,
public IOleObjectImpl<CEllispe>,
public IOleInPlaceActiveObjectImpl<CEllispe>,
public IOleInPlaceObjectWindowlessImpl<CEllispe>,
public IViewObjectExImpl<CEllispe>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CEllispe>,
publicIProvideClassInfo2Impl<&CLSID_Ellispe, &__uuidof(_IEllispeEvents), &LIBID_EllipseCaseLib>,
public CProxy_IEllispeEvents<CEllispe>,
public IQuickActivateImpl<CEllispe>,
public IDataObjectImpl<CEllispe>,
public CComCompositeControl<CEllispe>
ActiveX控件拥有界面,所以它只能存在于单线程套间中,所以应该用CComObjectRootEx<CComSingleThreadModel>;
ActiveX控件可以被创建,所以通过CComCoClass<CEllispe, &CLSID_Ellispe>来实现自己的类厂;
ActiveX控件至少要支持流方式保存,所以使用IPersistStreamInitImpl<CEllispe>;
VB和IE要求优先以属性包的方式保存对象,所以有的ActiveX控件也要支持
ActiveX控件支持结构化存储,这样可以被嵌入到OLE文档中,IPersistStorageImpl<CEllispe>;
ActiveX控件支持标准属性,使用CStockPropImpl<CEllispe, IEllispe>可以帮助节省时间;
ActiveX控件支持标准OLE控制功能,使用IOleControlImpl<CEllispe>;
ActiveX控件支持实地激活,使用public IOleObjectImpl<CEllispe>,public IOleInPlaceActiveObjectImpl<CEllispe>;
IOleInPlaceObjectWindowlessImpl<CEllispe>帮助实现快速高效的激活;
ActiveX控件支持按需呈现对象的视图,使用IViewObjectExImpl<CEllispe>;
ActiveX控件支持传递错误信息给调用方,而不是仅通过HRESULT,使用ISupportErrorInfo;
ActiveX控件支持事件,因此使用IConnectionPointContainerImpl<CEllispe>,IProvideClassInfo2Impl,CProxy_IEllispeEvents<CEllispe>,
ActiveX控件是复合控件,所以使用了CComCompositeControl<CEllispe>
由于我们在向导中选择了两个标准属性:BackGroundColor和BackGroundStyle,所以我们来看看idl文件中有些什么:
interfaceIEllispe : IDispatch{
[propput, bindable, requestedit, id(DISPID_BACKCOLOR)]
HRESULT BackColor([in]OLE_COLOR clr);
[propget, bindable, requestedit, id(DISPID_BACKCOLOR)]
HRESULT BackColor([out,retval]OLE_COLOR* pclr);
[propput, bindable, requestedit, id(DISPID_BACKSTYLE)]
HRESULT BackStyle([in]long style);
[propget, bindable, requestedit, id(DISPID_BACKSTYLE)]
HRESULT BackStyle([out,retval]long* pstyle);
};
IEllispe从IDispatch接口派生,这是因为控件容器要使用控件的IDispatch方法访问控件的属性和方法。
注意,所有的标准属性都有bindable和requestedit两个属性,这是因为标准属性的put方法在改变属性之前之后都要向包容器激发变化通知
四 标准属性
背景属性
背景颜色属于标准属性,CStockPropImpl类能够帮助我们。
template< class T, class InterfaceName, const IID* piid = &_ATL_IIDOF(InterfaceName), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
classATL_NO_VTABLE CStockPropImpl : public IDispatchImpl< InterfaceName, piid, plibid, wMajor, wMinor, tihclass >
{
public:
// Font
HRESULT STDMETHODCALLTYPE put_Font(IFontDisp* pFont)
{
__if_exists(T::m_pFont)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_Font/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_FONT) == S_FALSE)
return S_FALSE;
pT->m_pFont = 0;
if (pFont)
{
CComQIPtr<IFont, &__uuidof(IFont)> p(pFont);
if (p)
{
CComPtr<IFont> pFont;
p->Clone(&pFont);
if (pFont)
pFont->QueryInterface(__uuidof(IFontDisp), (void**) &pT->m_pFont);
}
}
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_FONT);
__if_exists(T::OnFontChanged)
{
pT->OnFontChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE putref_Font(IFontDisp* pFont)
{
__if_exists(T::m_pFont)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_Font/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_FONT) == S_FALSE)
return S_FALSE;
pT->m_pFont = pFont;
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_FONT);
__if_exists(T::OnFontChanged)
{
pT->OnFontChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE get_Font(IFontDisp** ppFont)
{
__if_exists(T::m_pFont)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_Font/n"));
ATLASSERT(ppFont != NULL);
if (ppFont == NULL)
return E_POINTER;
T* pT = (T*) this;
*ppFont = pT->m_pFont;
if (*ppFont != NULL)
(*ppFont)->AddRef();
}
return S_OK;
}
// Picture
HRESULT STDMETHODCALLTYPE put_Picture(IPictureDisp* pPicture)
{
__if_exists(T::m_pPicture)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_Picture/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_PICTURE) == S_FALSE)
return S_FALSE;
pT->m_pPicture = 0;
if (pPicture)
{
CComQIPtr<IPersistStream, &__uuidof(IPersistStream)> p(pPicture);
if (p)
{
ULARGE_INTEGER l;
p->GetSizeMax(&l);
HGLOBAL hGlob = GlobalAlloc(GHND, l.LowPart);
if (hGlob)
{
CComPtr<IStream> spStream;
CreateStreamOnHGlobal(hGlob, TRUE, &spStream);
if (spStream)
{
if (SUCCEEDED(p->Save(spStream, FALSE)))
{
LARGE_INTEGER l;
l.QuadPart = 0;
spStream->Seek(l, STREAM_SEEK_SET, NULL);
OleLoadPicture(spStream, l.LowPart, FALSE, __uuidof(IPictureDisp), (void**)&pT->m_pPicture);
}
spStream.Release();
}
GlobalFree(hGlob);
}
}
}
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_PICTURE);
__if_exists(T::OnPictureChanged)
{
pT->OnPictureChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE putref_Picture(IPictureDisp* pPicture)
{
__if_exists(T::m_pPicture)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_Picture/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_PICTURE) == S_FALSE)
return S_FALSE;
pT->m_pPicture = pPicture;
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_PICTURE);
__if_exists(T::OnPictureChanged)
{
pT->OnPictureChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE get_Picture(IPictureDisp** ppPicture)
{
__if_exists(T::m_pPicture)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_Picture/n"));
ATLASSERT(ppPicture != NULL);
if (ppPicture == NULL)
return E_POINTER;
T* pT = (T*) this;
*ppPicture = pT->m_pPicture;
if (*ppPicture != NULL)
(*ppPicture)->AddRef();
}
return S_OK;
}
// MouseIcon
HRESULT STDMETHODCALLTYPE put_MouseIcon(IPictureDisp* pPicture)
{
__if_exists(T::m_pMouseIcon)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_MouseIcon/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_MOUSEICON) == S_FALSE)
return S_FALSE;
pT->m_pMouseIcon = 0;
if (pPicture)
{
CComQIPtr<IPersistStream, &__uuidof(IPersistStream)> p(pPicture);
if (p)
{
ULARGE_INTEGER l;
p->GetSizeMax(&l);
HGLOBAL hGlob = GlobalAlloc(GHND, l.LowPart);
if (hGlob)
{
CComPtr<IStream> spStream;
CreateStreamOnHGlobal(hGlob, TRUE, &spStream);
if (spStream)
{
if (SUCCEEDED(p->Save(spStream, FALSE)))
{
LARGE_INTEGER l;
l.QuadPart = 0;
spStream->Seek(l, STREAM_SEEK_SET, NULL);
OleLoadPicture(spStream, l.LowPart, FALSE, __uuidof(IPictureDisp), (void**)&pT->m_pMouseIcon);
}
spStream.Release();
}
GlobalFree(hGlob);
}
}
}
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_MOUSEICON);
__if_exists(T::OnMouseIconChanged)
{
pT->OnMouseIconChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE putref_MouseIcon(IPictureDisp* pPicture)
{
__if_exists(T::m_pMouseIcon)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_MouseIcon/n"));
T* pT = (T*) this;
if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_MOUSEICON) == S_FALSE)
return S_FALSE;
pT->m_pMouseIcon = pPicture;
pT->m_bRequiresSave = TRUE;
if (pT->m_nFreezeEvents == 0)
pT->FireOnChanged(DISPID_MOUSEICON);
__if_exists(T::OnMouseIconChanged)
{
pT->OnMouseIconChanged();
}
pT->FireViewChange();
pT->SendOnDataChange(NULL);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE get_MouseIcon(IPictureDisp** ppPicture)
{
__if_exists(T::m_pMouseIcon)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_MouseIcon/n"));
ATLASSERT(ppPicture != NULL);
if (ppPicture == NULL)
return E_POINTER;
T* pT = (T*) this;
*ppPicture = pT->m_pMouseIcon;
if (*ppPicture != NULL)
(*ppPicture)->AddRef();
}
return S_OK;
}
IMPLEMENT_STOCKPROP(OLE_COLOR, BackColor, clrBackColor, DISPID_BACKCOLOR)
IMPLEMENT_STOCKPROP(OLE_COLOR, BorderColor, clrBorderColor, DISPID_BORDERCOLOR)
IMPLEMENT_STOCKPROP(OLE_COLOR, FillColor, clrFillColor, DISPID_FILLCOLOR)
IMPLEMENT_STOCKPROP(OLE_COLOR, ForeColor, clrForeColor, DISPID_FORECOLOR)
IMPLEMENT_BOOL_STOCKPROP(AutoSize, bAutoSize, DISPID_AUTOSIZE)
IMPLEMENT_BOOL_STOCKPROP(Valid, bValid, DISPID_VALID)
IMPLEMENT_BOOL_STOCKPROP(Enabled, bEnabled, DISPID_ENABLED)
IMPLEMENT_BOOL_STOCKPROP(TabStop, bTabStop, DISPID_TABSTOP)
IMPLEMENT_BOOL_STOCKPROP(BorderVisible, bBorderVisible, DISPID_BORDERVISIBLE)
IMPLEMENT_BSTR_STOCKPROP(Text, bstrText, DISPID_TEXT)
IMPLEMENT_BSTR_STOCKPROP(Caption, bstrCaption, DISPID_CAPTION)
HRESULT STDMETHODCALLTYPE put_Window(LONG_PTR hWnd)
{
return put_HWND(hWnd);
}
HRESULT STDMETHODCALLTYPE get_Window(LONG_PTR* phWnd)
{
return get_HWND(phWnd);
}
HRESULT STDMETHODCALLTYPE put_HWND(LONG_PTR /*hWnd*/)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_HWND/n"));
return E_FAIL;
}
HRESULT STDMETHODCALLTYPE get_HWND(LONG_PTR* phWnd)
{
__if_exists(T::m_hWnd)
{
ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_HWND/n"));
ATLASSERT(phWnd != NULL);
if (phWnd == NULL)
return E_POINTER;
T* pT = (T*) this;
*phWnd = reinterpret_cast<LONG_PTR>(pT->m_hWnd);
}
return S_OK;
}
IMPLEMENT_STOCKPROP(LONG, BackStyle, nBackStyle, DISPID_BACKSTYLE)
IMPLEMENT_STOCKPROP(LONG, BorderStyle, nBorderStyle, DISPID_BORDERSTYLE)
IMPLEMENT_STOCKPROP(LONG, BorderWidth, nBorderWidth, DISPID_BORDERWIDTH)
IMPLEMENT_STOCKPROP(LONG, DrawMode, nDrawMode, DISPID_DRAWMODE)
IMPLEMENT_STOCKPROP(LONG, DrawStyle, nDrawStyle, DISPID_DRAWSTYLE)
IMPLEMENT_STOCKPROP(LONG, DrawWidth, nDrawWidth, DISPID_DRAWWIDTH)
IMPLEMENT_STOCKPROP(LONG, FillStyle, nFillStyle, DISPID_FILLSTYLE)
IMPLEMENT_STOCKPROP(SHORT, Appearance, nAppearance, DISPID_APPEARANCE)
IMPLEMENT_STOCKPROP(LONG, MousePointer, nMousePointer, DISPID_MOUSEPOINTER)
IMPLEMENT_STOCKPROP(LONG, ReadyState, nReadyState, DISPID_READYSTATE)
};
我们先来看看模板参数
template < class T, class InterfaceName,
const IID* piid = &_ATL_IIDOF(InterfaceName), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
T是控件类的名字;
InterfaceName是接口的名字,该接口拥有标准属性和方法;
piid是接口的GUID的指针;
plibid是类型库GUID的指针;
wMajor是主版本号;
wMinor是次版本号;
实际运用中,只需要指定前面两个参数,其余皆可以采用默认值。
CStockPropImpl类为我们实现了所有标准属性的访问方法,但是我们只需要实现两个属性,因此我们只为我们需要的标准属性提供数据成员,成员变量的名称要与CStockPropImpl类使用的名字一致。如若不信,我们看看下面的宏
IMPLEMENT_STOCKPROP(OLE_COLOR, BackColor, clrBackColor, DISPID_BACKCOLOR)
该宏的定义如下:
#define IMPLEMENT_STOCKPROP(type, fname, pname, dispid) /
HRESULT STDMETHODCALLTYPE put_##fname(type pname) /
{ /
__if_exists(T::m_##pname) /
。。。。。。。。
所以CStockPropImpl类假定控件类T拥有m_clrBackColor成员变量
这很麻烦,但是不必烦恼,因为向导已经为我们定义了合适的成员变量。但是我们还是需要知道这些,万一我们不小心删除了代码,我们知道该如何恢复。
注意IMPLEMENT_STOCKPROP宏只能用于CStockPropImpl类
CEllispe类里边的属性声明为:
OLE_COLOR m_clrBackColor;
void OnBackColorChanged()
{
ATLTRACE(_T("OnBackColorChanged/n"));
}
OnBackColorChanged方法会被CStockPropImpl类在属性值修改的时候调用,如果我们需要对属性的修改进行即时反映,可以在该函数里面填写代码
其他属性也是如此。
现在我们的控件Ellipse已经拥有了背景颜色、背景状态两种标准属性,在Activex测试容器中右键点击控件的边缘,弹出菜单,选择属性,可以看到
我们可以设置背景颜色了。试着用用其他的功能,我们可以设置控件的环境属性,还可以把控件保存到流和结构化存储文件中。但是目前不支持属性包方式保存。
五 Unicode风格编码
我撰写本文的时候,正是Windows2000已经普及的时候,出于效率的考虑和开发程序减少从ANSI和UNICODE转换的额外负担,我在本文示例程序中全部使用Unicode风格编码,工程中设置如下:
六 用OpenGL绘制笛卡尔坐标系
到这里忍不住提高点难度,用GDI绘制笛卡尔坐标系很简单,用OpenGL绘制三维笛卡尔坐标系才棒。如果读者不想涉及太多的OpenGL技巧,可以掠过这一节,用GDI绘图。
在stdafx.h文件中增加以下代码:
#include<gl/gl.h>
#include<gl/glu.h>
#pragmacomment(lib, "opengl32.lib")
#pragmacomment(lib, "glu32.lib")
#pragmacomment(lib, "glaux.lib")
#pragmawarning(disable : 4100)
#include<gl/glaux.h>
#pragmacomment(lib, "winmm.lib")
为我们的控件添加成员函数
//设置屏幕DC的像素格式,OpenGL绘图环境初始化
BOOL CEllispe::bSetupPixelFormat(HDC hdc)
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1,                              // version number
PFD_DRAW_TO_WINDOW |            // support window
PFD_SUPPORT_OPENGL |          // support OpenGL
PFD_DOUBLEBUFFER,             // double buffered
PFD_TYPE_RGBA,                  // RGBA type
24,                             // 24-bit color depth
0, 0, 0, 0, 0, 0,               // color bits ignored
0,                              // no alpha buffer
0,                              // shift bit ignored
0,                              // no accumulation buffer
0, 0, 0, 0,                     // accum bits ignored
32,                             // 32-bit z-buffer
0,                              // no stencil buffer
0,                              // no auxiliary buffer
PFD_MAIN_PLANE,                 // main layer
0,                              // reserved
0, 0, 0                         // layer masks ignored
};
int pixelformat;
if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == 0 )
{
ATLASSERT(FALSE);
return FALSE;
}
if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE)
{
ATLASSERT(FALSE);
return FALSE;
}
return TRUE;
}
//初始化OpenGL绘制的环境
voidCEllispe::CreateContext(HDC hdc, RECT& rc)
{
PIXELFORMATDESCRIPTOR pfd;
if (!bSetupPixelFormat(hdc))
return;
int n = ::GetPixelFormat(hdc);
::DescribePixelFormat(hdc, n, sizeof(pfd), &pfd);
m_hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, m_hrc);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//绘制x、y、z坐标轴
voidCEllispe::RenderScene(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 10.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glColor3f(1.0f,1.0f,1.0f);
//绕x轴逆时针旋转15度
glRotatef(15.0f,1.0f,0.0f,0.0f);
//绕y轴顺时针旋转angle度
glRotatef(-30,0.0f,1.0f,0.0f);
glBegin(GL_LINES);
//绘制X轴
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(-100.0f,0.0f,0.0f);
glVertex3f(100.0f,0.0f,0.0f);
glVertex3f(100.0f,0.0f,0.0f);
glVertex3f(95.0f,0.0f,5.0f);
glVertex3f(100.0f,0.0f,0.0f);
glVertex3f(95.0f,0.0f,-5.0f);
//绘制Y轴
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(0.0f,-100.0f,0.0f);
glVertex3f(0.0f,100.0f,0.0f);
glVertex3f(0.0f,100.0f,0.0f);
glVertex3f(-5.0f,95.0f,0.0f);
glVertex3f(0.0f,100.0f,0.0f);
glVertex3f(5.0f,95.0f,0.0f);
//绘制Z轴
glColor3f(0.0f,0.0f,1.0f);
glVertex3f(0.0f,0.0f,-100.0f);
glVertex3f(0.0f,0.0f,100.0f);
glVertex3f(0.0f,0.0f,100.0f);
glVertex3f(5.0f,0.0f,95.0f);
glVertex3f(0.0f,0.0f,100.0f);
glVertex3f(-5.0f,0.0f,95.0f);
glEnd();
glPopMatrix();
glFinish();
SwapBuffers(wglGetCurrentDC());
}
在OnCreate里面添加如下代码:
LRESULT CEllispe::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
HDC hdc = GetDC();
RECT rc;
GetClientRect(&rc);
CreateContext(hdc, rc);
return 0;
}
在OnDestroy里面添加如下代码:
LRESULT CEllispe::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
::wglMakeCurrent(NULL, NULL);
if (m_hrc)
{
::wglDeleteContext(m_hrc);
m_hrc = NULL;
}
return 0;
}
在OnDraw里面添加如下代码:
HRESULT CEllispe::OnDraw(ATL_DRAWINFO& di)
{
HDC hdc = di.hdcDraw;
wglMakeCurrent(hdc, m_hrc);
RenderScene();
return __super::OnDraw(di);
}
最后一定要在CEllipse头文件中加上宏
BEGIN_MSG_MAP(CEllispe)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
CHAIN_MSG_MAP(CComCompositeControl<CEllispe>)
END_MSG_MAP()
效果如图:
另外发现一个问题glut库函数在ATL7.1中使用会导致工程生成的控件注册失败。
七自定义属性
我要为我的控件添加自己的属性,XColor,用来保存X轴的颜色。右键点击IEllipse接口,选择添加属性,
向导在idl文件中添加如下代码:
[propget, id(1), helpstring("属性XColor"), bindable, requestedit] HRESULT XColor([out, retval] OLE_COLOR* pVal);
[propput, id(1), helpstring("属性XColor"), bindable, requestedit] HRESULT XColor([in] OLE_COLOR newVal);
修改idl文件中的代码:
constint DISPID_XCOLOR=1;
[propget, id(DISPID_XCOLOR), helpstring("属性 XColor"), bindable, requestedit] HRESULT XColor([out, retval] OLE_COLOR* pVal);
[propput, id(DISPID_XCOLOR), helpstring("属性 XColor"), bindable, requestedit] HRESULT XColor([in] OLE_COLOR newVal);
向导在.h文件中增加如下代码:
STDMETHOD(get_XColor)(OLE_COLOR* pVal);
STDMETHOD(put_XColor)(OLE_COLOR newVal);
向导在.cpp文件中增加如下代码:
STDMETHODIMP CEllispe::get_XColor(OLE_COLOR* pVal)
{
// TODO: 在此添加实现代码
return S_OK;
}
STDMETHODIMP CEllispe::put_XColor(OLE_COLOR newVal)
{
// TODO: 在此添加实现代码
return S_OK;
}
现在我们来实现添加自己的代码实现属性:
第一步,先添加私有成员变量 OLE_COLOR m_XColor;
第二步,在get和put函数内部填写代码
STDMETHODIMP CEllispe::get_XColor(OLE_COLOR* pVal)
{
if(pVal==NULL)
return E_POINTER;
*pVal=m_XColor;
return S_OK;
}
STDMETHODIMP CEllispe::put_XColor(OLE_COLOR newVal)
{

ATL7 1编写ActiveX控件相关推荐

  1. 用C#编写ActiveX控件(三) 转载

    在前面我们已经完成了ActiveX控件的开发,接下来的就是发布它了. 首先,我们建立一个windows安装项目,并将ActiveX控件的主输出添加到项目输出中.然后,改动ActiveX控件的主输出文件 ...

  2. 关于《用C#编写ActiveX控件》的几点说明

    在我的第一篇blog发表之后,得到大家的支持,我的工作得到了认可,感到很开心.当然,很多朋友也提出了很多出色的见地.我想在这里说明一下我对这些问题的理解.         我所完成的控件是一个用来获取 ...

  3. [转]用C#编写ActiveX控件(一)

    前些日子做一个Web项目,必须自己编写一个ActiveX控件.如今的ActiveX控件大多是使用VB/C++来开发的,而我对他们并不熟悉,因此考虑使用熟悉的C#编写ActiveX控件. 首先,建立一个 ...

  4. 关于用C#编写ActiveX控件4(转)

    在前面我们已经完成了ActiveX控件的开发,接下来的就是发布它了. 首先,我们建立一个windows安装项目,并将ActiveX控件的主输出添加到项目输出中.然后,改动ActiveX控件的主输出文件 ...

  5. 关于用C#编写ActiveX控件2(转)

        了解了上述相关的理论之后,我们来看一个用C#编写ActiveX的实例. 首先,建立一个WinForm控件项目HelloWorld,并拖入一个Label控件,文字设为HelloWorld,如图: ...

  6. 用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件

    用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件 用C#编写ActiveX控件 开发浏览器控件这是本控件开发完成后的一个简单应用.我们可以利用它以本地文件夹为单位来批量更新服务器 ...

  7. 用C#编写ActiveX控件(二)

    原文地址为: 用C#编写ActiveX控件(二) 用C#编写ActiveX控件(二)                             Homer 在我的上一篇blog中,已经实现了一个最基本的 ...

  8. 用C#编写ActiveX控件(二) 转载

    在我的上一篇blog中,已经实现了一个最基本的ActiveX控件.当然,我们编写的任务还没有完成.首先,我们先尝试实现和JS的交互能力.        我们在Demo中加入ShowMessage方法: ...

  9. 关于用C#编写ActiveX控件3(转)

    在我的上一篇blog中,已经实现了一个最基本的ActiveX控件.当然,我们编写的任务还没有完成.首先,我们先尝试实现和JS的交互能力. 我们在Demo中加入ShowMessage方法: public ...

最新文章

  1. C++11多线程中std::call_once的使用
  2. 两位MIT学霸,25岁退学,40岁完成800亿IPO!
  3. 【CCNA考试】2010-06-29-北京-987(PASS)
  4. 博客网站没落的两个原因
  5. 小程序之通过参数改变标签
  6. Python中使用you-get库批量在线下载bilibili视频的教程
  7. Quartz2D简单绘制之不规则形状
  8. Https 加密原理分析
  9. cognos 7在IE7中不显示左边的树形菜单的解决
  10. Javascript获取For循环所用时间
  11. 让Apache日志不记录图片等指定扩展名文件的设置方法
  12. Exception processing template “xxx“: An error happened during tem
  13. HTML如何使用隐藏图片,css3如何隐藏图片?
  14. Knowledge Graph Embedding: A Survey of Approaches and Applications (2)
  15. 字体图标库(Font Awesome)的使用--绝佳的图标字体库和CSS框架
  16. “集五福”瓜分20亿!互联网巨头扎堆春节红包大战,暗藏啥玄机?
  17. 单字双字三字_古人取名有什么讲究?为什么有时候单字多有时候双字多?
  18. 为什么你的大脑那么喜欢图表?13张图告诉你
  19. 对“空间数据库”的理解
  20. 计算机组成原理经典复习题集锦(附答案)

热门文章

  1. 电力光缆是什么?常用电力光缆介绍
  2. oracle数据库游标是什么意思,oracle数据库游标用法详解
  3. linux 内核配置lcd,Linux-2.6.32.2内核在mini2440上的移植---添加LCD背光驱动
  4. Rasa项目中的文件都是干什么的?
  5. IDEA安装lombok插件后死活不生效
  6. 大学物理实验——分光计实验
  7. 【流行学习】局部保持投影(Locality Preserving Projections)
  8. 算法题:1000个苹果和10个箱子
  9. Hadamard Product求导案例
  10. 禅道测试用例自动化录入