您的位置:首页 > 其它

使用ATL开发一个ActiveX控件

2016-03-21 23:04 267 查看
一、创建项目
单击起始页中的“New Project…”,选择“ATL”分类下的“ATL Project”项目,项目名称为“Calculator”。
在随后出现的项目向导中,使用默认配置即可。
 
二、添加控件
在解决方案管理器中的项目上右击,
依次选择“Add”、“Class”,在添加类对话框中选择ATL分类下的ATL Control类型。
单击“Add”按钮,将会出现添加ATL Control向导。
在向导的第二步中,将接口类型选择为“Dual”,为控件支持事件做为准备,在Support选项中,选中“Connectionpoints”复选框。
随后出现选择控件要实现的接口的界面,除VS默认添加的实现外,再添加IObjectSafety接口,
实现该接口可以避免控件在IE中使用时IE弹出运行的脚本不安全的提示。 
 
三、为控件添加并实现方法
在Class View窗口中右击ICalc接口,依次选择“Add”、“Add Method…”,此处假定我们实现一个加法运算,将方法命名为“Add”,然后添加参数:
需要注意的是对返回值的处理。应将参数类型选定为DOUBLE*,并选中“retval”复选框。
向导结束后,VS自动在Calc.cpp中添加了该方法的空实现,略加修改后的方法代码为:
STDMETHODIMP CCalc::Add(DOUBLE a, DOUBLE b, DOUBLE* result)
{
*result = a + b;
return S_OK;
}
测试该方法:
由于只是调用该控件进行加法运算,并不需要该控件的界面展示,因此在测试控件之前,可以将VS自动生成的OnDraw方法中的其他代码删除,直接返回 S_OK 即可。
对VS自动生成的用于测试的htm略做修改来测试添加的方法。修改后的完整htm代码如下:
<HTML>
<HEAD>
<TITLE>ATL 8.0 test page for object Calc</TITLE>
</HEAD>
<BODY>
<OBJECT ID="Calc" CLASSID="CLSID:59443E6F-7B99-4F75-A7AF-6FEE5B8208CD"></OBJECT>
<input type="button" value="Add" onclick="add();" />
<script type="text/javascript">
function add() {
var calc = document.getElementById('Calc');
var result = calc.Add(2, 3);
alert(result);
}
</script>
</BODY>
</HTML>
四、为控件添加事件
假定控件进行的是一个非常复杂的运算,为了在调用运算时不阻塞调用者线程,可以使用异步方式完成运算。
控件在完成运算时需要通知调用者,这时便需要事件。
首先按照步骤三中的方法,添加一个异步调用加法运算的方法AddAsync,然后为控件添加运算完成的事件AddCompleted。
在Class View窗口中右击_ICalcEvents接口,
依次选择“Add”、“Add Method…”,根据添加方法向导添加AddCompleted方法。
然后在Class View窗口中右击CCalc类,依次选择“Add”、“Add ConnectionPoint…”,在弹出的实现连接点窗口中实现_ICalcEvents接口。
完成向导后,VS会自动为我们生成基本框架,包括引发事件的方法Fire_AddCompleted。
我们只需在AddAsync方法中添加运算并在运算结束时调用Fire_AddCompleted的代码:
STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
doubleresult;
result = a + b;
Fire_AddCompleted(&result);
return S_OK;
}
在网页中添加异步计算的代码进行测试(添加的javascript代码如下),应该能够得到我们想要的效果。
<script type="text/javascript">
function addAsync() {
var calc =document.getElementById('Calc');
calc.attachEvent("AddCompleted", OnAddCompleted);
calc.AddAsync(3, 4);
}

function OnAddCompleted(result){
alert(result);
}
</script><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
五、ActiveX控件的事件与多线程
细心的读者一定会发现步骤四中所谓的“异步”是假的:
虽然在运算结束后使用事件对调用者进行通知,但由于运算是在主线程上进行的,所以调用过程仍是同步的。
步骤四其实只是展示了一下事件的简单用法,如果真正实现异步,则需要在控件中使用多线程。
在ActiveX控件中使用多线程时需要注意的是:
引发事件(即调用Fire_XXXX)必须在窗口线程中进行,否则会导致事件不能被ActiveX控件的容器处理。
如果事件发生时执行代码的线程不是窗口线程。
那么应该使用PostMessage或SendMessage来通知窗口线程,并在消息处理函数中执行Fire_XXXX。
为了使用控件的消息机制,还应该在CCalc的构造函数中将m_bWindowOnly字段设置为TRUE。
以下是改为多线程后的部分示例代码:
STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
{
m_a = a;
m_b = b;
_beginthreadex(NULL, NULL,AddMethod, this, NULL, NULL);
return S_OK;
}
unsigned __stdcall CCalc::AddMethod(LPVOID arg)
{
CCalc* pThis = (CCalc*)arg;
pThis->m_result =pThis->m_a + pThis->m_b;
pThis->SendMessage(WM_ADDCOMPLETED);
return 0;
}

LRESULT CCalc::OnAddCompleted(UINT /*uMsg*/,WPARAM /*wParam*/, LPARAM /*lParam*/,BOOL& /*bHandled*/)
{
Fire_AddCompleted(&m_result);
return 0;
}
至此,一个简单的ActiveX控件就开发完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  activex