编写 ATL ActiveX 控件

一直想写一些ATL、ActiveX的东西,但是一直都没有下定决心去写,一来是自己对这方面的东西不太了解,写不出什么名堂;二来就是懒,懒得思考,懒得动手。这篇文章只是记录一下ATL ActiveX控件的一个大概写法跟使用方法,方便有这方面需求的同学快速上手。

一、ATL ActiveX控件编写

我做的是一个简单的图表控件,提供扇形图跟柱状图两种表现方式。

我们先简单列一下图表的成员属性:

1、图表样式:柱状图还是扇形图。

typedef enum _em_chart_type
	{
		ctNull,
		ctHistogram,
		ctPieChart
	} ChartType;
ChartType m_chartType;

2、图表中每一个项目的信息:名称、百分比和显示的颜色。

typedef struct _st_item_info
	{
		TCHAR		name[64];
		FLOAT		percent;
		OLE_COLOR	color;
	} ItemInfo;
std::list<ItemInfo><span style="white-space:pre">	</span>m_items;

3、图表是否显示:

VARIANT_BOOL m_bShow;

好了,只是一个简单的例子,就这么几个。

第二步我们来看看ActiveX控件创建的步骤:

1、新建一个ATL项目,确定。

2、添加一个ATL控件类,给控件一个名字,确定。

3、给我们的控件添加必要的属性设置。

点击完成后,我们可以看到VS自动给我们添加两个导出函数:

STDMETHOD(get_chartType)(SHORT* pVal);
STDMETHOD(put_chartType)(SHORT newVal);

4、给我们的控件添加一些必须的接口:

注意:ATL中函数的返回值添加,我们必须先选一个指针类型的参数,此时才能选择该参数是否作为输出参数还是返回值。

我添加的方法一共有下面几个:

STDMETHOD(Show)(VARIANT_BOOL bShow);
STDMETHOD(AddItem)(BSTR itemName, FLOAT itemPersent, OLE_COLOR itemColor, VARIANT_BOOL* bRet);
STDMETHOD(ClearItems)();

5、属性、方法添加完毕,完成代码。

5.1 图形绘制代码:

HRESULT OnDraw(ATL_DRAWINFO& di)
	{
		if(m_bShow)
		{
			switch(m_chartType)
			{
			case ctHistogram:
				return DrawHistogram(di);
			case ctPieChart:
				return DrawPieChart(di);
			}
		}
		return S_FALSE;
	}
HRESULT Chart::DrawHistogram(ATL_DRAWINFO &di)
{
	RECT& rc = *(RECT*)di.prcBounds;

	HPEN hPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
	if(NULL == hPen)
		return S_FALSE;
	SelectObject(di.hdcDraw, hPen);

	// draw the coordinate
	MoveToEx(di.hdcDraw, rc.left, rc.bottom - 5, NULL);
	LineTo(di.hdcDraw, rc.right, rc.bottom - 5);
	MoveToEx(di.hdcDraw, rc.left + 5, rc.bottom, NULL);
	LineTo(di.hdcDraw, rc.left + 5, rc.top);

	DeleteObject(hPen);
	hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	HPEN oldPen = (HPEN)SelectObject(di.hdcDraw, hPen);

	// items count
	int nNum = m_items.size();
	if(0 == nNum)
		return S_FALSE;

	// origin of the coordinate
	POINT ptOrg = { rc.left + 5, rc.bottom - 5 };
	// each rectangle's width
	DOUBLE dWidth = (DOUBLE)(rc.right - ptOrg.x) / (DOUBLE)(2 * nNum + 1);
	// one percent height
	DOUBLE dHeight = (DOUBLE)(ptOrg.y - rc.top) / 100.00;
	// item's index
	int nIdx = 0;

	std::list<ItemInfo>::const_iterator iter = m_items.begin();
	while(iter != m_items.end())
	{
		// paint area
		RECT rcPaint;
		rcPaint.left = ptOrg.x + (2 * nIdx + 1) * dWidth;
		rcPaint.right = rcPaint.left + dWidth;
		rcPaint.bottom = ptOrg.y;
		rcPaint.top = rcPaint.bottom - dHeight * (*iter).percent;

		HBRUSH hBrush = CreateSolidBrush((*iter).color);
		HBRUSH oldBrush = (HBRUSH)SelectObject(di.hdcDraw, hBrush);
		Rectangle(di.hdcDraw, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);

		SelectObject(di.hdcDraw, oldBrush);

		// continue to the next
		iter++;
		nIdx++;
	}

	SelectObject(di.hdcDraw, oldPen);
	return S_OK;
}
HRESULT Chart::DrawPieChart(ATL_DRAWINFO &di)
{
	// make it become a square
	RECT& rc = *(RECT*)di.prcBounds;
	if((rc.right - rc.left) > (rc.bottom - rc.top))
		rc.right = rc.left + rc.bottom - rc.top;
	else
		rc.bottom = rc.top + rc.right - rc.left;

	HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	if(NULL == hPen)
		return S_FALSE;
	HPEN oldPen = (HPEN)SelectObject(di.hdcDraw, hPen);

	// draw a circle
	Ellipse(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);

	const DOUBLE PI = 3.14159265;
	const POINT  ptCenter = { (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2 };
	const LONG	 R = ptCenter.x - rc.left;
	POINT		 ptOrg = { rc.right, ptCenter.y };
	POINT		 ptDst = ptOrg;
	DOUBLE		 dAngle = 0.0;

	// draw the pie chart one by one
	std::list<ItemInfo>::const_iterator iter = m_items.begin();
	while(iter != m_items.end())
	{
		// make the destination of the last time to become the original of this time
		ptOrg = ptDst;

		// select brush
		dAngle += (*iter).percent / 100.0 * 360.0;
		HBRUSH hBrush = CreateSolidBrush((*iter).color);
		HBRUSH oldBrush = (HBRUSH)SelectObject(di.hdcDraw, hBrush);

		// get ptDst
		ptDst.x = ptCenter.x + R * cos((360.0 - dAngle) * PI / 180.0);
		ptDst.y = ptCenter.y + R * sin((360.0 - dAngle) * PI / 180.0);

		// counterclockwise
		Pie(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom, ptOrg.x,
			ptOrg.y, ptDst.x, ptDst.y);

		SelectObject(di.hdcDraw, oldBrush);
		iter++;
	}

	SelectObject(di.hdcDraw, oldPen);
	return S_OK;
}
STDMETHODIMP Chart::Show(VARIANT_BOOL bShow)
{
	if(m_bShow != bShow)
	{
		m_bShow = bShow;
		FireViewChange();
	}
	return S_OK;
}

5.2 添加条目代码:

STDMETHODIMP Chart::AddItem(BSTR itemName, FLOAT itemPersent, OLE_COLOR itemColor, VARIANT_BOOL* bRet)
{
	if((itemPersent + GetTotalPercent()) > 100.0)
	{
		*bRet = S_FALSE;
		return S_FALSE;
	}

	ItemInfo ii = { 0 };
	wcscpy_s(ii.name, itemName);
	ii.percent = itemPersent;
	ii.color = itemColor;

	std::list<ItemInfo>::iterator iter = m_items.begin();
	while(iter != m_items.end())
	{
		if(itemName == (*iter).name)
		{
			*bRet = S_FALSE;
			return S_FALSE;
		}
		iter++;
	}

	m_items.push_back(ii);
	FireViewChange();
	return S_OK;
}

5.3 图表样式设置代码:

STDMETHODIMP Chart::get_chartType(SHORT* pVal)
{
	*pVal = (SHORT)m_chartType;
	return S_OK;
}

STDMETHODIMP Chart::put_chartType(SHORT newVal)
{
	if(newVal == (SHORT)m_chartType)
		return S_OK;

	switch(newVal)
	{
	case 0:
		m_chartType = ctNull;
		break;
	case 1:
		m_chartType = ctHistogram;
		break;
	case 2:
		m_chartType = ctPieChart;
		break;
	default:
		return S_FALSE;
	}

	FireViewChange();
	return S_OK;
}

二、控件测试程序编写:

控件完成之后,我们需要编写一个测试程序来展现它的样子。

1、创建一个MFC对话框程序。

2、插入我们刚写好的ActiveX控件,完成界面布局。

3、给我们的ActiveX控件关联一个变量。

关联变量完成后,我们可以看到VS自动给我们生成了一个chart.h跟chart.cpp文件。

4、编写代码。

// add item
void CAtlChartTestDlg::OnBnClickedBtnAdd()
{
	CString strName, strPercent;
	GetDlgItemText( IDC_EDIT_NAME, strName );
	GetDlgItemText( IDC_EDIT_PERCENT, strPercent );
	if( strName.IsEmpty() || strPercent.IsEmpty() )
	{
		AfxMessageBox( L"请输入正确的参数!" );
		return;
	}

	DOUBLE dPercent = _ttof( strPercent );
	COLORREF colorRef = m_btnColor.GetColor();

	m_chart.AddItem( strName, dPercent, colorRef );
}

// clear
void CAtlChartTestDlg::OnBnClickedBtnClear()
{
	m_chart.ClearItems();
}

// histogram
void CAtlChartTestDlg::OnBnClickedBtnHistogram()
{
	m_chart.put_ChartType( 1 );
}

// pie
void CAtlChartTestDlg::OnBnClickedBtnPie()
{
	m_chart.put_ChartType( 2 );
}

三、结果。

下面就是我们控件测试的结果展示:

添加4个条目:{111,12%,绿色},{222,13%,棕色},{333,55%,蓝色},{444,10%,黄色}

好了,完成。写的很简略,因为真的不知道该写什么。代码在这里可以下载:win7下activex控件例子

时间: 2024-10-21 16:16:08

编写 ATL ActiveX 控件的相关文章

Delphi 编写ActiveX控件(OCX控件)的知识和样例(有详细步骤)

一.ActiveX应用情况简介: ActiveX控件也就是一般所说的OCX控件,它是 ActiveX技术的一部分.ActiveX是微软公司推出的基于组件对象模型COM的技术,包括对Windows 32位应用编程接口(Win32 API)和组件对象模型的一系列扩充和增强,目标是把计算机桌面环境与因特网环境集成起来,同时保护在Windows技术中现有的开发投资.微软的 ActiveX技术根本上就是修改过的OCX技术,使它能够跨越Internet,主要是使用WWW来传递控件.            A

使用C#开发ActiveX控件(新)

前言 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是用C++或VB语言开发,本文介绍另一种方式,在.NET Framework平台上,使用C#语言开发ActiveX控件. 虽然本文通篇都在讲如何使用C#语言开发ActiveX控件,但我并不极力推荐使用这种技术,因为该技术存在明显的局限,即需要浏览器端安装.NET Framework(版本取决于开发Ac

使用VS2012创建ActiveX控件

最近接到一个小项目,要求编写一个ActiveX控件嵌入IE运行.查了下资料,Delphi要求先制作VCL控件,然后从VCL控件生成ActiveX控件:VC查到的都是vc6.0下面的创建步骤,向导创建完代码后,使用类向导添加控件的属性和方法: Automation 选项中添加方法和属性会自动在接口和控件源代码中生成相应的代码,如果是私有(自定义)的方法不需要暴露给接口的,可以手工添加生成. 但是到了VS2012中,类向导中没有了这个Automation选项卡,再此只能添加变量和方法函数,并且也不能

C#制作ActiveX控件及部署升级(摘自网络)

使用C#开发ActiveX控件 控件开发.制作CAB包.签名.部署 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是用C++或VB语言开发,本文介绍另一种方式,在.NET Framework平台上,使用C#语言开发ActiveX控件. 虽然本文通篇都在讲如何使用C#语言开发ActiveX控件,但我并不极力推荐使用这种技术,因为该技术存在明显的局限,即需

ActiveX控件(ATL篇)

目录 第1章 VC++6.0创建    2 1.1 目标    2 1.2 创建项目    2 1.3 增加COM类    4 1.4 属性    7 1.5 事件    8 1.6 实现连接点    9 1.7 编码    11 1.7.1 增加成员变量    11 1.7.2 初始化成员变量    11 1.7.3 完成属性赋值代码    11 1.7.4 完成控件绘制代码    11 1.7.5 响应鼠标左键按下消息    13 1.7.6 修改DllUnregisterServer   

[activeX]使用ATL开发ActiveX控件[转]

本文描述了使用ATL开发一个ActiveX控件的完整过程. 一.创建项目 单击起始页中的"New Project-",选择"ATL"分类下的"ATL Project"项目,项目名称为"Calculator".在随后出现的项目向导中,使用默认配置即可. 二.添加控件 在解决方案管理器中的项目上右击,依次选择"Add"."Class",在添加类对话框中选择ATL分类下的ATL Control

ActiveX控件是什么?

一.ActiveX的由来 ActiveX最初只不过是一个商标名称而已,它所涵盖的技术并不是各自孤立的,其中多数都与Internet和Web有一定的关联.更重要的是,ActiveX的整体技术是由Microsoft的COM(Component Object Model,组件对象模型)构筑的.但不要误认为ActiveX是定义了所有包含基于COM的技术.COM与Microsoft Office和Windows以及Microsoft现在所做的一切都有关联,但显然这些产品并不是ActiveX家族中的成员.

剖析ActiveX控件安全问题

Dissect ActiveX Control Safety 1.介绍 如果你曾经在网页或者ASP中使用过com对象,你可能会发现,有时候会出现这样讨厌的对话框     这是因为你的控件没有被标记为安全的,对于初始化不安全或者对于脚本不安全,甚至兼而有之.你每打开一次这样的网页,这种情况就会发生一次,你怎么办?当然,这可以通过设置IE本身的安全等级为low来解决这样的问题,但是如果你要制作一个可发布的控件,你能想象到每一位用户在使用你制作的控件时都要且列抱怨这种强制行为:或者如果你是其中一个使用

ActiveX控件(MFC篇)

目录 第1章 VC++6.0创建控件    1 1.1 目标    1 1.1.1 方法    1 1.1.2 属性    1 1.1.3 事件    1 1.2 创建项目    2 1.3 项目结构    6 1.3.1 COM接口    6 1.3.2 COM类    7 1.3.3 属性页    7 1.3.4 应用程序类    8 1.3.5 注册与注销    8 1.4 方法    9 1.4.1 增加    9 1.4.2 删除    11 1.5 属性    12 1.5.1 Te