初试ActiveX控件
这几天看了关于COM技术的资料并看了孙鑫老师关于ActiveX控件的教程,自己就动手实践了一下。教程中用的是VC6.0实现的,我用的是vs2010,在实践的过程中也遇到了一些问题,最终都解决了。在这里将学习过程分享一下。
ActiveX控件的底层实现是基于COM技术的。任何一个控件都有自身的属性、方法、事件。那么我们自己在开发ActiceX空间的时候,也可以为其添加属性、方法、事件,这些属性、方法、事件不仅包括标准的属性、方法、事件也包括自定义的属性、方法、事件。我们先在VS中建立MFC ActiveX Control的应用程序。然后我们就可以开发自己的ActiveX控件了。
一、注册控件
开发的控件或者系统安装的控件可以在任何程序开发环境是使用,使用之前必须先进行注册,向注册表写入信息,否则开发环境是无法知道系统中的控件的。我们自己开发的控件在编译过程中会自动调用regsvr32应用程序为我们的控件进行注册。在我们的开发环境中用于注册的操作时通过DllRegisterServer()函数实现的,响应的反注册函数为DllUnregisterServer(),当然我们也可以手动的注册、反注册我们的ActiveX控件,方法是在运行进程中输入regsvr32 E:\studio\Clock\Debug\Clock.ocx 反注册regsvr32 /u E:\studio\Clock\Debug\Clock.ocx 当然路径根据实际情况而定。注册完成之后就可以在其他应用程序中使用这个ActiveX控件了。
一个ActiveX控件不能单独运行,必须在某个容器中运行,我们在开发过程中可用vs自带的测试容器进行测试。但是在安装vs2010时这个测试容器应用程序并没有安装,我们可以在vs的安装目录下的Sample文件夹下找到一个VC2010Samples.zip的压缩文件。在这个路径下有一个测试程序VC2010Samples\C++\MFC\ole\TstCon,经过编译后就会有一个测试用的可执行文件,我们可以在这个容器中测试我们开发的ActiveX控件。
二、为控件添加属性
(1)为控件添加标准属性
这个示例程序是编写一个显示当前系统时间的控件,我们可以为该控件添加标准的改变背景和前景颜色的属性。在vc6.0中可以通过Class Wizard为其添加属性,但是在vs中我没发现如何添加。但是可以在类视图的接口中右键单击添加属性,我们为其添加标准的属性BackColor和ForeColor,我们可以在Ctrl类的OnDraw()函数中添加如下代码实现改变背景和前景颜色的功能:
CBrush brush(TranslateColor(GetBackColor()));
pdc->FillRect(rcBounds,&brush);
pdc->SetBkMode(TRANSPARENT);
pdc->SetTextColor(TranslateColor(GetForeColor()));
(2)为控件添加自定义属性
我们不仅能为控件添加标准属性,也可以为其添加自定义属性,该示例控件的功能是显示系统当前时间,每隔一秒刷新一次,我们可以让用户自定义刷新时间。该实例中我们为其添加外部属性名InterVal的属性,添加完成后,系统自动为我们添加一个OnIntervalChanged()的成员函数,当该属性发生变化时,就会调用该函数来处理用户的属性设置。示例代码如下:
if (m_Interval<0||m_Interval>6000)
{
m_Interval=1000;
}
else
{
m_Interval=m_Interval/1000*1000;
KillTimer(1);
SetTimer(1,m_Interval,NULL);
BoundPropertyChanged(0x1);
}
(3)为控件添加属性表单
每一个控件自身都有一个属性表单供使用者改变该控件的属性,我们创建的工程自动为其添加一个属性页,我们可以为其添加多个属性页。
首先为其添加改变背景和前景颜色的属性页。我们可以在Ctrl的源文件添加如下加粗显示的代码:
BEGIN_PROPPAGEIDS(CClockCtrl, 2)
PROPPAGEID(CClockPropPage::guid)
PROPPAGEID(CLSID_CColorPropPage)
END_PROPPAGEIDS(CClockCtrl)
在这个宏之间,我们可以添加标准属性的属性页代码。这样就可以生成一个改变颜色的属性页了。
我们可以在系统自动生成的空的属性页上添加编辑框,让用户输入刷新时间。我们可以为该编辑框关联成员变量和属性名,让该编辑框控件和开发的控件的时间相关联。在VC6.0中,可以很方便的使用Class Wizard同时关联成员变量和属性。但是在vs中只能通过向导关联成员变量,必须手动关联属性。我们可以在PropPage类的DoDataExchange()中添加控件与属性的关联。示例如下:
DDP_Text(pDX, IDC_EDIT1, m_updateInterval,_T("Interval"));
三、为控件添加方法
为控件添加方法跟添加属性的过程一样,添加后在接口中有方法的定义,在Ctrl类中有方法的实现。
四、为控件添加事件
控件通过接口发送事件通知,容器实现接口中的方法。
(1)为控件添加标准事件
在VC6.0中可以通过Class Wizard为控件添加事件,或者在事件接口上右键单击添加事件,但是在vs中以上方法好像不能添加,不过可以在Ctrl类上单击右键可以为控件添加事件。我们可以很方便的为控件添加标准事件。
(2)为控件添加自定义事件
可以通过同样的方法为事件添加自定义事件。在Ctrl类的源文件中可以完成自定义事件的实现,当某一事件发生时,可以调用该函数通过FireEvent()函数向容器发送事件通知。在OnDraw()函数中添加响应时间。
五、属性的持久性
我们开发的控件在具体的使用过程中,可以改变其属性值,但是当我们关闭程序,再一次打开应用程序时,会发现我们添加的标准属性仍然保持我们以前设置的属性值,而添加的自定义属性不能保持我们上次设置的属性值,这在实际应用中是很不方便的。所以我们要设法保持属性的持久性。我们可以在Ctrl类的DoPropExchange()函数中添加如下代码实现:
PX_Short(pPX,_T("Interval"),m_Interval,1000);
六、通知容器属性发生变化
当我们在实际应用过程中,我们在控件自身的属性表单中改变属性,但是我们会发现属性表单中属性值的变化不会反映到开发环境的属性上,这样会给使用者造成误解。我们可以让其同步。我们可以在OnIntervalChanged()函数中通过BoundPropertyChanged(0x1)函数使指定的属性通知容器也发生改变。
七、改变控件的环境属性
我们可以让控件在设计状态下不运行,而在运行时才运行。但是控件自身不会感知自己处于何种状态,而容器知道自身处于何种状态。我们可以通过控件的环境属性通知控件此时处于何种状态,然后做出相应的操作。AmbientUserMode( )函数可以感知容器处于何种状态。具体实现代码如下:
if(AmbientUserMode())
InvalidateControl();
运行结果: