基于MFC的ActiveX控件开发.docx
《基于MFC的ActiveX控件开发.docx》由会员分享,可在线阅读,更多相关《基于MFC的ActiveX控件开发.docx(98页珍藏版)》请在冰点文库上搜索。
基于MFC的ActiveX控件开发
基于MFC的ActiveX控件开发
ActiveX控件是基于组件对象模型(COM)的可重用软件组件,广泛应用于桌面及Web应用中。
在VC下ActiveX控件的开发可以分为三种,一种是直接用COM的API来开发,这样做显然非常的麻烦,对程序员要求也非常高,因此一般是不予考虑的;一种是基于传统的MFC,采用面向对象的方式将COM的基本功能封装在若干MFC的C++类中,开发者通过继承这些类得到COM支持功能。
MFC为广大VC程序员所熟悉,易于上手学习,但缺点是MFC封装的东西比较多,因此用MFC开发出来的控件相对会比较大,因此比较适于开发桌面ActivexX控件,尤其是有GUI界面的控件。
第三种就是基于ATL的,ATL可以说是专门面向COM开发的一套框架,使用了C++的模板技术,在运行时不需要依赖于类似MFC程序所需要的庞大的代码模块,更适合于Web应用开发。
本文介绍的是采用第二种方式,即应用MFC进行桌面可视控件开发的方法步骤,开发环境则是基于VC2005。
1.创建控件项目
打开VC2005后,我们要先创建一个项目,在新建项目页的左侧选择VisualC++-MFC,在右侧选择MFCActiveX控件,填上解决方案和项目名称,比如在这里我的项目名称是activexdemo1,解决方案名称是activexdemo。
然后进入控件向导页,在向导的第二页有个运行时许可证,选中这个的话会在生成控件的同时生成一个许可证文件,其他用户在使用这个控件的时候必须同时附有这个许可证,在此我们保持默认状态,不选。
下一页是关于项目中各部分的命名问题,可以根据需要自定义,这里就按默认的情况不做修改了。
下一页是选择控件基于哪种控件的扩展以及控件的一些基本特性。
如果新建的控件是基于某种特定控件的话,就在创建的控件基于下选择所要继承的控件名,否则就保持none。
下方的附加功能根据实际需要进行选择,并且可以将鼠标放置于选项上方,功能的说明会自动显示在动态出现的小提示信息窗口中。
选择完毕点击完成,向导就根据你的选择生成新项目。
进入开发环境,我们可以先看一下类视图。
其中的Cactivexdemo1App是我们这个控件的主程序模块,定义了控件的注册(DllRegisterServer)、删除(DllUnregisterServer)等功能,一般不用动,如有需要我们可以在其中的InitInstance和ExitInstance中定义我们自己的初始化和终止操作代码,一般也就是一些资源的初始化和销毁工作。
Caxtivexdemo1Ctrl是控件类,我们要做的控件功能基本上就是要在这个类中实现。
需要提一下的是在这个类中重写了父类的OnDraw函数,有如下两句代码:
pdc->FillRect(rcBounds,CBrush:
:
FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
也就是在控件上画了一个椭圆,实际控件开发中可以根据功能需要修改重写这个函数来绘制控件界面。
Caxtivexdemo1PropPage是属性页类,这个类实现了一个在开发时设定控件属性的对话框。
activexdemo1Lib是为客户程序提供本控件的属性、方法以及可能响应的事件的接口的库节点,在添加控件的这些功能的时候会用得到。
其中的Cactivexdemo1App是我们这个控件的主程序模块,定义了控件的注册(DllRegisterServer)、删除(DllUnregisterServer)等功能,一般不用动,如有需要我们可以在其中的InitInstance和ExitInstance中定义我们自己的初始化和终止操作代码,一般也就是一些资源的初始化和销毁工作。
Caxtivexdemo1Ctrl是控件类,我们要做的控件功能基本上就是要在这个类中实现。
需要提一下的是在这个类中重写了父类的OnDraw函数,有如下两句代码:
pdc->FillRect(rcBounds,CBrush:
:
FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
也就是在控件上画了一个椭圆,实际控件开发中可以根据功能需要修改重写这个函数来绘制控件界面。
Caxtivexdemo1PropPage是属性页类,这个类实现了一个在开发时设定控件属性的对话框。
activexdemo1Lib是为客户程序提供本控件的属性、方法以及可能响应的事件的接口的库节点,在添加控件的这些功能的时候会用得到。
设置项目属性将配置类型设置成静态库(.lib)
2.生成并测试控件
好,现在我们就可以先来生成一下这个项目,当然到目前我们只是用系统自动生成的一个控件项目,什么功能都没有,只是一个空框架。
几秒钟后,项目应该是顺利生成。
控件也被自动注册到系统中去。
那怎么才能测试一下这个控件呢?
当然你可以再建个新项目,比如一个对话框程序,在对话框资源编辑窗口中右边的工具箱里鼠标右键菜单里点选择项。
从弹出窗口中的COM组件下找到我们刚刚生成的这个控件,打勾选中。
然后在工具箱里就会出现这个控件。
然后用鼠标拖到对话框里就能用这个控件了。
除了这种方法,VS还提供了一种简便的控件测试工具。
在VisualStudio中菜单的工具下有个ActiveX控件测试容器。
在工具栏里点新控件按钮。
在插入控件对话框中找到并选择我们的这个控件。
然后就能在这个容器中测试控件的各种功能了。
3.事件
ActiveX控件使用事件通知容器控件上发生了某些事情。
事件的常见示例包括单击控件、使用键盘输入数据和控件状态更改。
当发生这些操作时,控件将引发事件以提醒容器。
MFC支持两种事件:
常用和自定义。
常用事件是COleControl类自动处理的事件。
自定义事件使控件得以在该控件特定的操作发生时通知容器。
控件内部状态发生更改或收到某个窗口消息即属于此类事件。
常用事件
常用事件由COleControl类自动引发。
COleControl包含预定义成员函数,它们引发常见操作所导致的事件。
一些由COleControl 实现的常见操作包括单击和双击控件、键盘事件和鼠标按钮状态发生更改。
添加常用事件的操作是在类视图中右击ActiveX控件类,比如在此例中就是Caxtivexdemo1Ctrl。
在菜单中选择添加事件,打开添加事件向导。
在添加事件向导中的事件名称中选择Click,也就是鼠标点击事件,添加到控件中。
然后再选中类视图中库节点下的第三个节点,也就是Dactivexdemo1Events。
在下面就能看到我们刚刚添加的这个事件。
然后生成新的控件程序,我们来看看测试一下这个新事件。
打开上面提到的ActiveX控件测试容器,把这个控件添加进来,用鼠标点击控件,就会在程序下方的消息栏中看到activexdemo1Control:
Click这样的消息,这就是我们添加进去的鼠标相应事件。
那在开发环境中使用控件的时候是什么样子的呢?
好,像上面提到过的那样新建一个对话框项目,把控件放到对话框上。
选中这个控件,在属性窗口中的控件事件中就有这个Click事件了,如果在使用控件中需要相应鼠标点击事件,就点添加ClickActivexdemo1ctrl1,事件响应函数中添加你需要的功能了。
比如像这样:
voidCtestMFCDlg:
:
ClickActivexdemo1ctrl1()
{
//TODO:
在此处添加消息处理程序代码
MessageBox(_T(“Hi.”));
}
编译运行这个测试程序,点击控件位置就会弹出带有Hi.字样的MessageBox。
自定义事件
自定义事件与常用事件的区别在于,自定义事件不由COleControl类自动引发。
自定义事件将控件开发人员确定的某一操作识别为事件。
添加常用事件的操作是在类视图中右击ActiveX控件类,比如在此例中就是Caxtivexdemo1Ctrl。
在菜单中选择添加事件,打开添加事件向导。
定义一个叫做MyEvent的事件,事件可以带参数,比如我们加个BSTR的参数msg。
然后,回到类视图,这次选中库节点下的第三个节点,也就是_Dactivexdemo1Events,在下面就会看到新添加的这个事件。
再选中类视图中的控件类,即Cactivexdemo1Ctrl,下面也会出现一个MyEvent函数。
双击这个MyEvent可以看到定义代码如下:
voidMyEvent(BSTR msg)
{
FireEvent(eventidMyEvent,EVENT_PARAM(VTS_PI1),msg);
}
这里的这个MyEvent(BSTRmsg)函数就是用于触发MyEvent事件用的,什么意思呢,就是说当在控件中需要出发自定义的这个MyEvent的时候调用这个MyEvent(BSTRmsg)就可以了。
下面结合例子看看是怎么回事。
比如说我们希望用户鼠标双击左键的时候触发这个事件,就这么来作。
选中类视图中的控件类,即Cactivexdemo1Ctrl,然后在消息窗口中找到WM_LBUTTONDBCLK,添加这个消息的处理函数。
在消息处理函数中如下修改:
voidCactivexdemo1Ctrl:
:
OnLButtonDblClk(UINTnFlags,CPointpoint)
{
//TODO:
在此添加消息处理程序代码和/或调用默认值
MyEvent(_T(“HI,MyEvent.”));
COleControl:
:
OnLButtonDblClk(nFlags,point);
}
这样每次用户在双击控件的时候就会触发我们自定义的MyEvent事件了。
然后看一下测试效果。
打开ActiveX控件测试容器,添加这个控件,然后双击控件,看消息框里出现什么了?
由于双击自然也就是两次单击,所以会同时出现两种事件。
activexdemo1Control:
MyEvent{msg=72}
activexdemo1Control:
Click
打开测试项目,控件的控件事件里就多了一个MyEvent事件。
添加一个针对此事件的处理函数MyEventActivexdemo1ctrl1(LPCTSTRmsg),msg就是我们定义事件时的那个msg参数,在上面的定义中我们是传递了一个”HI,MyEvent.”字符串消息。
现在看看是不是这个样子。
在MyEventActivexdemo1ctrl1函数中我们显示一个MessageBox,把msg参数打印出来。
voidCtestMFCDlg:
:
MyEventActivexdemo1ctrl1(LPCTSTRmsg)
{
//TODO:
在此处添加消息处理程序代码
MessageBox(msg);
}
同时注意要把上面常用事件中定义的Click事件的处理函数ClickActivexdemo1ctrl1注释掉,然后编译运行程序后双击控件就会弹出HI,MyEvent.对话框。
也就是说,由于双击操作触发了我们定义的MyEvent事件,进而调用MyEvent的处理函数。
4.方法
方法就是控件开放给用户使用的一些功能函数,类似于C++的类函数。
控件方法分两类,一类是常用方法,其实现由父类COleControl提供。
自定义方法由开发人员定义,由此向用户提供自定义的功能实现。
常用方法
COleControl支持两个常用方法:
DoClick和Refresh。
Refresh由控件的用户调用,用以立即更新控件的外观;而调用DoClick是用于引发控件的Click事件。
添加常用方法的操作是在类视图中打开库节点,在本例中就是activexdemo1Lib节点。
选中第二个节点,也就是本例中的_Dactivexdemo1,在右键菜单中选择添加方法,打开添加方法向导。
在方法名中选择需要添加的常用方法。
比如DoClick。
然后在类视图中选中_Dactivexdemo1,就会在下面看到我们刚才添加的那个常用方法。
同时,你也可以在这里看到有一个AboutBox方法,这是系统自动给我们添加进去的,功能是显示一个About窗口,这个窗口可以在项目的资源视图中的Dialog下找到并编辑。
同样也要验证一下这个新添加的方法。
还是打开ActiveX控件测试容器,添加此控件,然后点击工具栏上的这个红色方框,也就是调用方法。
在调用方法对窗口的方法名中选中我们刚添加的这个DoClick方法,然后点击调用。
还记得这个DoClick是干什么的来着吗?
,对了,它是要引发Click事件的,上面介绍事件的时候我们已经添加了Click这个常用事件了,那么现在调用DoClick也就是要引发我们在上面添加的这个Click事件了,于是在测试容器主窗口的消息框中出现了activexdemo1Control:
Click。
那么在开发环境中是什么效果呢?
好,再回到刚才那个测试项目里。
我们先在窗体上添加一个按钮,就叫DoClick,等会用点击它的方式来调用DoClick方法。
然后为了方便操作,我们先给刚才添加到对话框中的那个控件添加一个绑定的对象变量。
鼠标右击控件选择添加变量。
在添加成员变量向导中添加与此控件绑定的控件变量,比如叫做m_activexdemo。
然后,双击刚才新加到窗体上的那个按钮,即添加这个按钮的鼠标点击事件函数中,如下添加一行代码,即调用控件的DoClick方法。
voidCtestMFCDlg:
:
OnBnClickedButton1()
{
//TODO:
在此添加控件通知处理程序代码
m_activexdemo.DoClick();
}
最后,编译运行测试程序,点击DoClick按钮,结果弹出Hi.对话框。
这就是说,我们通过执行控件对象的DoClick方法引发了控件的鼠标点击事件,因此上文常用事件一节中我们添加的事件处理函数ClickActivexdemo1ctrl1被执行了。
自定义方法
自定义方法与常用方法的区别在于,自定义方法未由COleControl实现。
必须为添加到控件的每个自定义方法提供实现。
添加自定义方法的操作是在类视图中打开库节点,在本例中就是activexdemo1Lib节点。
选中第二个节点,也就是本例中的_Dactivexdemo1,在右键菜单中选择添加方法,打开添加方法向导。
在添加方法向导里添加需要自定义的方法的名称、返回值和参数。
注意这里有个内部名称,默认情况是与上面的方法名一样,但是也可以修改为其他名,这个内部名称是方法在控件类内的函数名称,比如这里我们的方法名为MyThod,则选中类视图中的库接口下的第二个节点,下面会出现刚定义的MyMethod方法。
而选中控件类Cactivexdemo1Ctrl,下面会看到在这个类中定义的方法名称就是我们上面指定内部名称MyMethodInner。
而方法的具体功能也就是在这个内部函数中实现。
比如我们如下定义MyMethodInner:
voidCactivexdemo1Ctrl:
:
MyMethodInner(LPCTSTRmsg)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//TODO:
在此添加调度处理程序代码
MessageBox(msg);
}
也就是说要弹出一个消息对话框,消息内容就是参数中传递的字符串。
然后来测试一下效果,首先还是ActiveX控件测试容器,打开调用方法窗口,在方法名中会看到我们定一个MyMethod,选择之,然悔会在参数区看到我们定义的msg参数,选中,然后在下面参数值中填入你想传递给参数的值,比如hello,然后点击设置值,最后点击调用,MyMethodInner就会被执行,也就是弹出hello消息窗口。
然后再看一下使用控件开发的时候的效果。
回到测试项目,还记得那个DoClick按钮吧,还是用这个,不过有点小问题,因为上面我们为这个控件绑定控件变量的时候还没有这个自定义方法,所以在绑定的时候生成的控件类定义中没有这个方法,就无法测试了。
为了省事,我们就干脆新建一个项目,像前文提到的那样添加控件,绑定控件变量,在DoClick的单击事件中写入如下代码:
voidCt1Dlg:
:
OnBnClickedButton1()
{
//TODO:
在此添加控件通知处理程序代码
m_activexdemo.MyMethod(_T(“Thisismymethod.”));
}
编译执行,点击DoClick按钮,就会看到那个Thisismymethod消息框了。
5.属性
属性是ActiveX控件中向所有容器公开的数据成员。
与事件和方法类似,也分为常用属性和自定义属性。
常用属性
常用属性已由COleControl类实现。
COleControl类包含支持控件的通用属性的预定义成员函数。
某些通用属性包括控件的标题以及前景色和背景色。
添加常用属性的操作是在类视图中打开库节点,在本例中就是activexdemo1Lib节点。
选中第二个节点,也就是本例中的_Dactivexdemo1,在右键菜单中选择添加属性,打开添加属性向导。
选中实现类型下的常用,在属性名下选择要添加的属性,比如在此我们选择的是Caption。
然后在类视图中就能看到新添加的这个属性。
这个Caption也就是我们在使用控件进行开发的时候,控件属性窗口中的那个Caption属性。
在开发环境中我们可以用控件变量的GetCaption和SetCaption来获取和设定控件的这个属性。
比如在测试项目中的DoClick按钮的点击事件函数中如下修改:
voidCt1Dlg:
:
OnBnClickedButton1()
{
//TODO:
在此添加控件通知处理程序代码
MessageBox(m_activexdemo.GetCaption());
m_activexdemo.SetCaption(_T(“change”));
MessageBox(m_activexdemo.GetCaption());
}
这样在点击DoClick按钮的时候会显示控件的Caption名称对话框,然后修改名称,再把修改后的名称显示在弹出的对话框中。
如果是在ActiveX控件测试容器中的话,我们还是打开调用方法窗口,在方法名中会看到Caption(ProPut)和Caption(ProGet)的方法,也就是对应上面的SetCaption和GetCaption,同样在这里也可以试着给Caption修改内容并获取修改后的值。
自定义属性
自定义属性与常用属性的区别在于,自定义属性未由COleControl类实现。
自定义属性用于将ActiveX控件的某个状态或外观向使用该控件的程序员公开。
添加自定义属性的操作是在类视图中打开库节点,在本例中就是activexdemo1Lib节点。
选中第二个节点,也就是本例中的_Dactivexdemo1,在右键菜单中选择添加属性,打开添加属性向导。
这里自定义属性有成员变量和Get/Set方法两种。
成员变量属性
我们先看一下成员变量这种属性。
根据需要选择属性的类型,并填入属性名,同时变量名和通知函数会被自动填入,如不满意默认的名称也可以手动修改这两个名称。
其中这个变量名是作为控件类的一个成员变量来存储控件属性的,比如选中类视图中的的控件类,也就是Cactivexdemo1Ctrl,就会在下面看到这个m_MyProp1成员变量。
这种自定义属性的使用与常用属性类似,在ActiveX控件测试容器中也是有着MyProp1(ProPut)和MyProp1(ProGet)这样的方法以供测试时调用,在开发时也会有属性出现在控件的属性窗口中,在程序中也是可以通过GetMyProp1和SetMyProp1来获取和设置属性值。
而通知函数是当这个属性被修改是所触发的一个函数。
被定义为控件类中的一个成员函数。
举个例子,假如我们在这个函数中写入如下代码:
voidCactivexdemo1Ctrl:
:
OnMyProp1Changed(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//TODO:
在此添加属性处理程序代码
MessageBox(_T(“MyProp1Changed.”));
SetModifiedFlag();
}
然后在ActiveX控件测试容器中调用MyProp1(PropPut)来修改这个属性值,则会弹出这个对话框。
同样的,在开发时如果在属性窗口中修改此属性值或在代码里修改此属性值都会触发这个通知函数,进而弹出我们代码中的对话框。
Get/Set方法型属性
添加Get/Set方法型属性则是在添加属性向导窗口中的实现类型中选中Get/Set方法,指定属性类型和属性名,向导会自动填入Get和Set函数,同时可以指定自定义的参数。
然后在控件类的定义中就会出现GetMyProp2(void)和SetMyProp2(LPCTSTRnewVal)两个函数,分别用于获取和设置属性值。
但要注意的是,如果看一下这两个函数的代码的话,这两个自动生成的函数实际上并没有真正起到获取和设置属性值的功能,这只是两个框架,基本上什么也没做,如果放在ActiveX控件测试容器中调用这两个函数的话会看不到什么反应,于是就还需要我们来手动定义函数的具体功能。
比如说我们可以为控件类添加一个成员变量用来存储我们的属性值,由于我们这个属性定义的是BSTR类型,我们可以把添加的这个成员变量声明为CStringm_MyProp2,然后分别修改GetMyProp2(void)和SetMyProp2(LPCTSTRnewVal)为如下:
BSTRCactivexdemo1Ctrl:
:
GetMyProp2(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CStringstrResult(m_MyProp2);
//TODO:
在此添加调度处理程序代码
returnstrResult.AllocSysString();
}
voidCactivexdemo1Ctrl:
:
SetMyProp2(LPCTSTRnewVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//TODO:
在此添加属性处理程序代码
m_MyProp2=newVal;
SetModifiedFlag();
}
然后在ActiveX控件测试容器中先调用SetMyProp2给属性赋值,然后用GetMyProp2就能返回刚才新赋的属性值了。
另外要注意的是,刚才定义这个属性的时候,参数列表是留空的,默认得到的就是上面SetMyProp2和GetMyProp2两个函数,如果在参数列表里添加了其他参数的话,那么新加的参数就会被添加到这两个函数的参数列表中去。
比如我们添加个BSTR型属性MyProp3,在参数列表里加上一个LONGarg参数,那么得到的两个函数将是GetMyProp3(LONGarg)和SetMyProp3(LONGarg,BSTRnewVal)。
6.属性页