activex控件开发教程,active x 控件

  activex控件开发教程,active x 控件

  本文源代码和文档下载

  本章的目标:

  完成本章后,您将能够:

  了解什么是ActiveX控件。

  如何基于MFC编写ActiveX控件

  掌握如何测试ActiveX控件

  掌握如何测试ActiveX控件

  了解如何注册ActiveX控件要点:ActiveX控件的实现、测试和注册。

  本章将介绍ActiveX控件的应用和工作原理。我们可以把ActiveX控件想象成一个微小的服务器应用程序,它不能独立运行,必须嵌入容器程序中,与容器一起运行。然后,容器相当于一个客户端程序,它使用ActiveX提供的服务。

  注:本文改编自孙鑫的教程,并在此基础上增加了活动控件与网页的交互。

  1.1什么是ActiveX控件Activex控件是微软提供的一种强大的编程开发技术。ActiveX是基于OLE和COM的开发技术。它既是一个自动化对象,也是一个COM对象。根据微软的权威软件开发指南MSDN(Microsoft Developer

  网络),ActiveX控件,原名OLE控件或OCX控件,是一些可以插入网页或其他应用程序的软件组件或对象。在窗体中,Activex控件是带有后缀ocx的控件。但是读者要注意,ActiveX控件对应的文件也可以有其他后缀,比如。dll。

  典型的ActiveX控件有三个特征:方法、属性和事件。

  1.2 ActiveX控件的好处在实际编程中,我们可以将常用的功能封装在一个ActiveX控件中,然后将控件提供给VB或Delphi的开发人员。例如,我们开发了一个中国地图控件。就一家公司有很多分店,比如麦当劳,会在全国不断增加加盟店。麦当劳总部需要每个月实时观察这些新增加盟店的地理位置。所以麦当劳可以直接购买我们开发的这个地图控件,在地图上显示他们分店的位置,而不是自己开发这个控件。现在很多公司都在开发ActiveX控件,把一些常用的功能封装成一个Activex控件,然后提供给其他公司或者终端用户直接使用。

  1.3用MFC编写基本的ActiveX控件。接下来我们用v c++写一个ActiveX控件,可以用MFC ActiveX。

  适用于我的控件向导

  生成ActiveX控件程序的框架。它为MFC ActiveX控件的开发提供了很好的支持。至于ActiveX,它的底层其实是用COM技术实现的。但是,通过使用MFC ActiveX ControlWizard,即使我们不了解COM,也可以开发出一个功能完善的ActiveX控件。

  这个例子将开发一个时钟控件。在v c++开发环境中,选择[文件\新建]菜单项,在打开对话框中选择项目选项卡,在列表框中选择MFC。

  Activex向导,项目名称设置为:Clock。单击[确定]按钮进入MFC ActiveX

  ControlWizard向导的第一步,如下图所示:

  这里,第一个选项的功能是询问用户在这个项目中要提供的控件的数量。注意:一个文件可以包含多个ActiveX控件。在本例中,我们为上述所有选项选择了默认值。

  点击【下一步】按钮进入MFC ActiveX。

  ControlWizard向导的第二步,如下图所示。

  单击“完成”创建一个MFC ActiveX控件项目。正如我们所看到的,MFC

  ActiveX控件向导向导创建的项目自动生成三个类,如下图所示:

  CClockApp类派生自COleControlModule类,后者的派生层次结构如下图所示。

  可以看到,COleControlModule类是从CWinApp类派生出来的,所以可以看作是一个应用类,它的实例代表了控制程序本身。也就是说,CClockApp类相当于单个文档应用程序的application类。

  CClockCtrl类派生自COleControl类,其派生层次结构如下图所示:

  可以看到,COleControl类是从CWnd类派生出来的,所以它也是一个窗口类,相当于单文档应用程序中的主窗口类,或者说是一个可视化类,所以控制窗口上的所有操作都会在CClockCtrl类中完成。在这个类中,你可以看到它提供了一个OnDraw函数,当控件窗口被重绘时,这个函数将被调用。如果控件需要输出图形,可以在这个函数中编写相应的实代码。

  我们先来看看CClockCtrl类头文件中的一些内容:

  //消息

  maps //{{AFX_MSG(CClockCtrl)

  //注意class wizard将添加和移除

  这里是成员函数。

  //不要编辑您在这些内容中看到的内容

  生成的代码块!

  //}}AFX_MSG

  声明消息映射()

  //

  调度地图

  //{{AFX_DISPATCH(CClockCtrl)

  //注意class wizard将添加和移除

  这里是成员函数。

  //不要编辑您在这些内容中看到的内容

  生成的代码块!

  //}}AFX_DISPATCH

  DECLARE_DISPATCH_MAP()

  afx _ msg void about box();

  //

  事件地图

  //{{AFX_EVENT(CClockCtrl)

  //注意class wizard将添加和移除

  这里是成员函数。

  //不要编辑您在这些内容中看到的内容

  生成的代码块!

  //}}AFX_EVENT

  声明事件映射()

  我们可以看到,这个文件不仅提供了一个消息图,还提供了一个时间表图和一个事件图。调度映射是MFC提供的一种映射机制,主要是供外部应用程序方便地访问控件的属性和方法,而事件映射也是MFC提供的一种映射机制,允许控件向包含它的容器发送事件通知。我们将在稍后向时钟控件添加方法和属性时使用这两个映射。

  CClockPropPage类派生自COlePropertyPage类,后者的派生层次结构如下图所示:

  如您所见,COlePropertyPage类是从CDialog类派生的,后者在类似于对话框的图形界面中显示自定义控件的属性。也就是说,CClockPropPage类用于显示时钟控件的属性页。

  另外,读者可以看到这个项目中还有另外两个内容:_ DCOCK和_DClockEvents。在妈妈们面前,有一个像勺子一样平躺的图标(),表示对应的项目是接口,接口是控制与外部程序通信的协议。接口可以看作是函数的集合,外部程序可以通过这个接口公开的方法访问控件的属性和方法。实际上,接口可以看作是一个抽象的基类。该接口定义的所有函数都是纯虚函数,这些函数的实现都是在CClockCtrl类中完成的。通过MFC的底层封装,CClockCtrl类继承自接口:_ DCOCK,所以通过这个接口调用的函数实际上调用的是CClockCtrl类中实际实现的函数。ActiveX控件中的界面类似于计算机硬件的界面。比如在计算机硬件中,主板和显卡的通信是通过主板上的插槽来完成的,也就是主板和显卡的接口。一旦我们做出这个接口,我们就可以任意选择一个主板和一个显卡进行通信。因为接口是标准的,所以可以选择任何厂商的主板和显示器,只要它们的接口符合通用标准。通过主板接口公开的方法调用显卡的显示函数,显卡需要实现接口公开的方法。显卡相当于这里的ActiveX控件,主板相当于与控件通信的外部容器。如果两个通信实体希望通过接口进行通信,那么其中一个实体必须实现接口公开的方法,而另一个实体通过接口调用这些方法。下面是ActiveX控件实现接口公开的方法,容器调用这些方法。至于接口的底层实现,需要了解一些COM的基础知识,读者有兴趣可以自行查阅相关资料。在这种情况下,由于MFC提供的封装,底层细节是不可见的。

  这里我们使用Build(F7)命令生成时钟控制程序,然后在项目所在目录的Debug目录下,我们可以看到生成了一个Clock.ocx文件,这是程序生成的ActiveX控件文件。使用时只需要将这个文件传递给用户,注册后就可以使用控件了。

  1.4 ActiveX控件的测试当我们在VC开发环境下运行时钟程序时,会出现如下对话框,让用户选择一个可执行的程序。

  如前所述,ActiveX控件不能独立运行,它必须嵌入到容器中才能运行。因此,我们可以点击对话框上标有右箭头的按钮,弹出如下快捷菜单。

  您可以选择ActiveX控件测试。

  容器]菜单项,也就是说,我们选择ActiveX

  测试容器这个应用程序作为时钟控件的容器,位于微软Visual Studio安装目录的Commaon\Tools子目录下,程序名为TSTCON32.EXE。如果与该应用程序相对应的菜单项没有出现,您可以选择[浏览]菜单项,然后找到TSTCON32.EXE程序并选择它。

  最后点击【确定】按钮,ActiveX控件测试将会打开。

  容器应用程序,如下所示

  然后,我们可以通过选择[编辑\插入新内容]来加载特定的ActiveX控件

  控制…]菜单项,则弹出如下对话框

  然后在对话框左侧的列中选择任意一个控件,然后快速连续按键盘上的[C]、[L]、[O]键,就可以直接定位到我们刚刚生成的时钟控件。

  然后单击对话框上的[确定]按钮关闭对话框。这时,在ActiveX控件测试中

  容器应用程序中加载了时钟控件,这个ActiveX控件的当前功能是绘制椭圆,如下图所示:

  当然,我们也可以新建一个VC对话框项目进行测试,命名为ClockTest。如果您想将ActiveX控件添加到对话框资源中,请在对话框资源上单击鼠标右键,并从弹出的快捷菜单中选择[插入]。

  微软倡导的ActiveX网络化多媒体对象技术

  控制…]菜单项,将显示以下对话框。在此对话框中,找到并选择时钟控件,然后单击[确定]按钮关闭对话框。

  此时,时钟控件被插入到对话框资源中。

  在VC中,插入ActiveX控件的另一种方法是选择[项目\添加到]

  项目\组件和控件…]菜单项,将显示以下对话框:

  在此对话框中,双击已注册的ActiveX。

  Controls”目录,找到该目录下的时钟控件并选中,如下图所示:

  然后点击【插入】按钮,在将显示的确认对话框上点击【确定】按钮,弹出如下对话框:

  当以这种方式插入ActiveX控件时,将为项目中的控件生成一个类。这里为时钟控件生成了一个类,类名为CClock,基类为CWnd。该类是控件的封装类。它封装了一些访问这个ActiveX控件的操作。单击[确定]按钮关闭对话框。此时,在ClockTest项目的ClassView选项卡上,可以看到增加了一个类:CClock,它提供了一些功能。我们只需要调用这些函数来访问Clock这个ActiveX控件的方法和属性。同时,时钟控件的图标被添加到工具箱中,如下图所示:

  我们只需要点击图标,在对话框资源上拖放一个合适的区域来放置一个时钟控件。如下图:

  1.5 ActiveX控件的注册所有的ActiveX控件都必须先注册才能使用。实际上,在VC开发环境下生成时钟控制程序时,输出窗口如下图所示:

  我们看到注册的ActiveX

  Control…,表示在生成时钟控制程序时,VC环境已经为我们注册了控件。实际上,VC是调用regsvr32程序来完成这个操作的编译器。

  如果要删除ActiveX控件的注册信息,可以使用Regsvr32程序的/u选项。我们可以选择系统的[开始\运行]命令,然后在对话框上的打开编辑框控件中输入regsvr32。

  /u,然后输入要删除的ActiveX控件的完整路径,如下图所示。

  点击【确定】按钮,弹出如下信息对话框:

  消息框提示“DllUnregisterServer in”

  D:\Code\Clock\Debug\Clock.ocx成功.这里DllUnregisteredServer是一个函数,而且是ActiveX控件提供的函数。命令“regsvr32 /u”的执行实际上是调用指定控件的DllUnregisterServer函数来删除控件的注册信息。对于regsvr32程序来说,它不知道需要删除哪些信息,所以它只是调用控件的DllUnregisterServer函数,这个函数删除了注册表中控件的注册信息。

  删除注册表中时钟控件的信息后,如果是在ActiveX控件中测试

  当容器程序试图再次加载时钟控件时,在控件列表中找不到它。

  如果想再次注册时钟控件,仍然可以选择regsvr32程序,但是不需要使用/u选项。其他同上。将显示以下对话框。

  在此信息框中提示:“DllRegisterServer in

  D:\Code\Clock\Debug\Clock.ocx成功.同样,DllRegisterServer是ActiveX控件提供的一个功能。当执行regsvr32命令时,它实际上调用指定控件的DllRegisterServer函数,并将控件的信息写入注册表。所以实际上ActiveX控件的注册和注销都是利用控件本身提供的两个函数来完成的,regsvr32程序只调用这两个函数。注册完成后,在ActiveX控件测试中

  你可以在容器程序的控件列表中找到时钟控件。

  1.6时间控件的实现接下来,继续实现时钟控件来显示当前系统时间,可以在CClockCtrl类的OnDraw函数中完成。此时,该函数中已经自动生成了两行代码,分别用于填充控件的背景和绘制椭圆。我们将首先注释这两个代码,然后添加以下代码:

  空的

  CClockCtrl:OnDraw( CDC* pdc,const CRect

  rcBounds,const CRect rcInvalid)

  {

  //TODO:用您的替换下面的代码

  自己的绘图代码。

  //pdc- FillRect(rcBounds,

  CB rush:from handle((HBRUSH)GetStockObject(WHITE _ BRUSH)));

  //PDC-Ellipse(RC bounds);

  得到字符串表示的时间

  time=CTime:GetCurrentTime();

  CString

  str=时间。格式(" % H:% M:% S ");

  pdc- TextOut(0,0,str);

  }

  如果要获取当前系统时间,可以使用CTime类的静态方法:GetCurrentTime,该方法将返回一个表示当前系统时间的CTime对象。然后可以使用CTime对象的Format方法对获取的CTime类型时间进行格式化,返回一个CString对象,然后在控制窗口中显示显示时间的字符串。

  在VC开发环境中,使用Build命令生成时钟控制程序并运行,如下图所示:

  但是,此时控件显示的时间仍然是。为了让时间“动起来”,我们需要设置一个定时器,让它每隔一秒发送一条WM_TIMER消息。在响应定时器的消息处理函数中,让控件刷新并重新处理当前系统时间。这里,我们需要在创建控制窗口后设置计时器。为此,我们需要在CClockCtrl类中添加一个WM_CREATE消息处理函数,然后在创建控制窗口后调用SetTimer函数来创建计时器。具体代码如下:

  (同Internationalorganizations)国际组织

  cclock ctrl:OnCreate(LPCREATESTRUCT LPCREATESTRUCT){

  if(cole control:OnCreate(lpCreateStruct)==

  -1)

  return-1;

  //TODO:添加您的专用创建代码

  这里

  SetTimer(1,1000,NULL);

  返回0;

  }

  接下来将Windows message: WM_TIMER的处理添加到CClockCtrl类中,调用其响应函数OnTimer中的Invalidate函数使窗口失效,这样就可以重画窗口了。具体实现代码如下:

  void cclock ctrl:on timer(UINT nIDEvent)

  { //TODO:在此添加您的消息处理程序代码

  和/或调用默认

  invalidate();

  cole control:on timer(nIDEvent);

  }

  并运行构建时钟控件,您将看到这个时钟控件显示的时间随着当前系统时间而变化。

  1.7属性读者可以发现VB中提供了如下图所示的属性面板,通过该面板可以修改控件属性的值。在面板的左侧,列出了控件的一些属性。对于时钟控件,目前我们没有为它添加任何属性,都是MFC ActiveX。

  由ControlWizard自动生成的属性;面板的右侧是属性的相应值。例如,控件的Name属性是Clock1。如果我们想改变时钟控件的前景色和背景色,我们找到了时钟控件的前景色和背景色,但是在时钟控件的属性面板中看不到这两个属性。但是,如果你在VB程序的窗体上放置一个列表框控件,那么你可以看到控件在属性面板上有BackColor和ForeColor属性,可以用来设置控件的背景色和前景色。如果你想为时钟控件提供这样的属性,让用户可以设置控件的前景色和背景色,那么你就需要在VC开发环境下继续改进时钟控件,给它添加这样的属性。

  1.7.1标准属性在VC开发环境中,如果要给控件添加属性,可以通过ClassWizard来实现。首先,打开“类向导”对话框,选择“自动化”选项卡,然后单击[添加]

  属性….]按钮,将出现如下图所示的添加属性对话框:

  在此对话框中,单击“外部”。

  名称(外部名称)下拉列表框,您会看到出现的列表框中有许多属性。这些是MFC为ActiveX控件提供的标准属性,包括BackColor(背景色)和ForeColor(前景色)属性。如果你想给控件添加一个标准属性,只需从列表中选择这个属性,比如选择BackColor,保持默认股票选项选中,点击【确定】按钮,给控件添加背景。然后以同样的方式将ForeColor属性添加到时钟控件中。此时,时钟控件的“自动化”选项卡的内容如下图所示:

  你可以看到,新增加的两个属前面有一个“S”符号,下面的提示表明它们是一个“库存属性”,即常规或保留属性。ActiveX控件中有四个属性。

  Stock:为每个控件提供的标准属性,如字体或颜色。

  L Ambient:控件周围的环境属性3354已被放入容器属性中。这些属性不能更改,但控件可以使用它们来调整自己的属性。

  L Extended:这些是容器处理的属性,一般包括大小和在屏幕上的位置。

  L Custom:由控件开发人员添加的属性。

  单击上图所示对话框中的[确定]按钮,关闭ClassWizard对话框。然后在VC开发环境中的类视图选项上的_DClock接口下,可以看到增加了BackColor和ForeColor两个属性。

  使用Build命令再次生成时钟控制。

  1.7.2自定义属性目前时钟控件每1秒更新一次时间的显示。接下来,我们向时钟控件添加一个自定义属性:time interval。用户设置该属性的值后,时钟控件根据用户指定的时间间隔值更新显示的时间。

  此时,您还需要使用ClassWizard向时钟控件添加属性,还需要选择ClassWizard对话框上的Automation选项卡,然后单击[Add]

  属性]按钮,将弹出添加属性的对话框。该对话框中有几个内容,其中外部

  Name(外部名称)是在集成开发环境(如VB和Variable)中看到的控件属性的名称

  Name(变量名)是在VC集成开发环境中开发该控件时使用的该控件类的成员变量。也就是说,开发程序中使用了变量。

  该名称访问控件属性,但在外部使用控件时,使用external。

  访问名称控件的属性。这里我们将新添加的时间间隔属性的外部名称设置为Inverval,选择类型为short,并自动将变量名设置为m_interval。ClassWizard自动为该控件添加一个通知函数:OnIntervalChanged(如下图所示),在外部修改该属性时会调用该函数。

  如您所见,添加属性对话框中提供了三个单选按钮,但此时只有两个选项可供选择。默认选择是成员变量。选中该选项时,ClassWizard会为该属性生成一个成员变量和一个通知函数,如上图所示;如果您选择获取/设置

  方法选项,则“添加属性”对话框如下图所示。可以看到,在添加属性对话框中,没有两个选项,即成员变量和通知函数。ClassWizard会自动为这个属性生成两个函数:SetInterval和GetInterval。在程序中,如果要设置Interval属性的值,可以调用SetInterval函数;如果想获得这个属性的值,可以调用GetInterval函数。但是在控件内部,如果要保存Interval的值,就需要自己定义一个成员变量。正如我们刚刚看到的,如果您选择成员变量选项,ClassWizard将自动生成这样一个成员变量。在此示例中,将保留默认设置,即选择成员变量选项。

  然后,单击添加属性对话框上的[确定]按钮完成间隔属性的添加,并单击ClassWizaard对话框上的[确定]按钮关闭ClassWizard对话框。此时,在VC开发环境中,在ClassView选项卡上,可以看到_DClock接口中增加了另一个属性:Interval,CClockCtrl类中增加了一个函数:OnIntervalChanged。当Interval的外部属性被修改时,将调用这个OnIntervalChanged函数。该函数的默认实现代码如下:

  空的

  cclock ctrl:OnIntervalChanged(){

  //TODO:添加通知处理程序

  密码

  SetModifiedFlag();

  }

  可以看到,在这个函数中调用了一个名为SetModifiedFlag的函数。根据字面意思,可以猜测这个函数是用来设置属性被修改的标志的。

  另外可以发现,ClassWizard还为CClockCtrl类提供了一个成员变量:m_interval,其定义代码如下:

  //调度映射//{{AFX_DISPATCH(CClockCtrl)

  短m _ interval

  afx_msg无效

  OnIntervalChanged();

  //}}AFX_DISPATCH

  DECLARE_DISPATCH_MAP()

  可以看到,添加的m_interval和OnIntervalChanged函数的定义位于CClockCtrl类的调度映射中。如前所述,调度映射主要是为了让外部应用程序方便地访问控件的属性和方法。

  接下来,我们根据用户在OnIntervalChanged函数中输入的时间间隔值来控制时钟控件的显示更新。具体代码如下:

  空的

  cclock ctrl:OnIntervalChanged(){

  //TODO:添加通知处理程序

  密码

  如果

  (m_interval 0m_interval 6000)

  {

  m _ interval=1000

  }

  其他

  {

  m _ interval=m _ interval/1000 * 1000;

  }

  kill timer(1);

  SetTimer(1,m_interval,NULL);

  SetModifiedFlag();

  }

  因为时间间隔不能是负数,也不能太大。因此,在OnIntervalChanged函数中,首先判断m_interval变量的值。如果用户设置的间隔属性值小于0或大于6000,则间隔值被设置为1000。否则,调整,即对用户输入的值进行四舍五入,得到整数秒。接下来调用KillTimer函数销毁之前设置的定时器(其ID为1),时间间隔由时钟控件的m_interval属性值设置。

  使用Build命令生成最新的时钟控件,然后使用ActiveX控件测试。

  容器容器测试控件。使用编辑\插入新内容

  控件…]命令插入控件后,为了测试控件的属性,需要选择控件,然后点击[控件\调用]

  方法…]菜单项,将显示以下对话框:

  在此对话框中,有一个方法名称(方法

  Name)下拉列表,列表中列出了当前控件提供的方法,如下图所示:

  如果要获取一个属性的值,应该选择Propet类型的方法;如果你想设置一个属性的值,你应该选择Propet类型的方法。这里我们要设置时钟控件的interval属性的值,所以我们要选择Interval(适当的)项,在后面出现的对话框的参数编辑框中输入值:2000,点击【设置

  Value]按钮,然后将Interval属性的值设置为2000,如下图所示。

  但是,此时这个属性值还没有生效,所以需要点击【调用】按钮。之后你会发现时钟控件显示的时间每隔2秒跳一次,表示设置生效。

  1.8方法,为时钟控件添加自定义方法。同样,这是通过使用ClassWizard完成的。首先,打开“类向导”对话框,并选择“自动化”选项卡。注意:必须为该属性页上的类名选项选择CClockCtrl。然后,[添加

  方法]按钮,然后会出现如下对话框:

  此对话框中提供了几个选项,其中包括外部名称(外部

  Name)是在对外部程序使用控件的方法时使用的。在这里,我们可以将其设置为Hello。如您所见,系统自动为此方法提供了一个内部名称:hello。这个内部名称是控件内部使用的方法名称,它可以不同于外部名称。然后将返回类型设置为void,不为此方法设置参数。如下所示:

  然后单击[确定]按钮关闭“添加方法”对话框,并单击“类向导”对话框上的[确定]按钮关闭对话框。此时,在ClassView选项中,可以看到_DClock接口下增加了一个方法:Hello,这个方法的前面用一个绿色的小方块表示。同时CClockCtrl类中提供了该方法的实现,该方法的实现代码为空。在这个方法中,我们可以使用MessageBox函数显示一个消息框,其字符串为:“Hello

  世界!"。具体代码如下:

  void CClockCtrl:Hello() {

  //TODO:添加调度处理程序代码

  这里

  MessageBox("Hello world!");

  }

  使用Build命令生成最新的时钟控件,并再次使用ActiveX控件测试。

  容器容器测试控件。在这个容器中调用控件方法的步骤是:选择时钟控件,选择【控件\调用】

  方法…]菜单项,调用方法对话框将被打开,此对话框的方法

  在名称下拉列表框中选择“Hello”方法,然后点击[Invoke]按钮调用时钟控件的Hello方法,会出现下图所示的消息框:

  1.9事件ActiveX控件有两种事件:标准事件和自定义事件。

  1.9.1标准事件在VC中。如果要向时钟控件添加事件,可以使用ClassWizard来完成。首先,打开“类向导”对话框及其“ActiveX事件”选项卡。在该选项卡上,确保在类名组合框中选择了CClockCtrl。然后单击[添加]

  事件]按钮,将显示添加事件对话框,其中有一个名为外部的对话框。

  名称,当你点击它右边的向下箭头时,会看到这个列表框中列出了一些准备好的事件(如下图所示),也就是MFC提供的一些标准事件,比如Click事件。这里,我们先为时钟控件添加一个标准事件,即股票事件。在外部

  从名称下拉列表中选择单击,保持默认股票选项不变,然后单击[确定]按钮关闭添加。

  事件对话框,并单击类向导对话框上的[确定]按钮关闭对话框。

  这时在ClassView标签页中可以看到_DClockEvents接口下已经添加了一个method: Click,就是刚刚添加的Click事件。为什么添加的事件是添加到_DClockEvents接口而不是放入_DClock接口?读者可以在Clock.odl文件的末尾看到下面的代码片段:

  //的类信息

  CClockCtrl

  [

  uuid(8377 e215-598d-4f 31-8 bde-0 e 16 aff 83 a9 a),

  帮助字符串(“时钟控制”),控制

  ]

  玻璃钟

  {

  [默认]调度接口

  _ DClock

  [默认,源]调度接口

  _ DClockEvents

  };

  在上面显示的代码中,可以看到在_DClockEvents接口前面有一个“source”标志,但是在_DClock接口前面没有这个标志。“source”标志表示_DClockEvents接口是一个源接口。源接口指示控件将使用此接口发送通知事件,该接口不是由控件本身实现的接口。如前所述,当双方使用接口进行通信时,一方必须调用接口公开的方法,另一方必须实现接口提供的方法。我们现在实现的时钟控件只是调用_ DCLockeEvents接口提供的方法,向容器发送事件通知。既然控件使用了_ DCLockeEvents接口提供的方法,那么谁负责实现这个方法呢?实际上,_ DCLockeEvents接口中的方法是由容器实现的。容器知道源接口是通过一种机制在控件中定义的,所以它实现该接口。在这里,读者可能想知道为什么容器实现的接口是由控件定义的。一方面,对于每个控件来说,它可以有自己的事件接口,但是容器无法提前知道控件将使用哪个事件接口发出通知,所以我们在编写控件的同时指定事件接口,并将其标识为源接口。另一方面,谁定义接口并不重要。比如主板和显卡通信,是主板厂商定义接口,还是显卡厂商定义接口,或者两者共同定义接口。都一样。关键是通信双方可以按照一个接口进行通信。

  现在,我们已经为时钟控件添加了一个标准事件:Click,并再次使用ActiveX控件测试。

  容器容器测试控件。插入时钟控件后,在该控件上单击鼠标左键。这时可以在容器下面的窗口中看到下面这句话:时钟控件:click,触发时钟控件的Click事件,如下图所示:

  我们也可以使用新创建的VC项目ClockTest进行测试,打开[ClassWizard]并选择[Message]

  Maps]选项卡,选择IDC_CLOCKCTRL1,我们发现它对应的是一个点击消息,就是我们刚刚为时钟控件添加的点击事件。如下图所示:

  点击【增加功能…】,为其增加一条消息处理,如下图:

  单击[确定]关闭对话框,然后单击类向导上的[编辑代码]添加消息响应代码:

  空的

  CClockTestDlg:onclickclockctrl 1(){

  //TODO:添加控件通知处理程序

  此处代码

  MessageBox("点击时钟");

  }

  为了编译程序,我们在时钟控件上单击鼠标左键,弹出如下消息框:

  这是因为在时钟控件上单击鼠标左键时,控件接收到click消息,于是使用_ DCLockeEvents的接口中的方法(即click方法)向容器(即ClockTest对话框)发送事件通知,因为_ DCLockeEvents的源接口是由容器实现的,相当于控件调用容器的Click方法,实际调用的是OnClickClockctrl1的消息响应函数中的代码。

  1.9.2自定义事件在VC中,为了给ActiveX控件添加自定义事件,也可以使用ClassWizard来完成,与上面添加标准事件的过程相同。另外,在项目的ClassView选项卡上,右键单击_DClockEvents接口,从弹出的快捷菜单中选择[Add]。

  事件…]菜单项,也可以打开添加事件对话框。使用此对话框,我们为时钟控件添加一个自定义事件。新添加事件的外部名称设置为:NewMinute,系统会自动将事件的内部名称设置为:FireNewMinute。结果如下:

  单击【OK】按钮对话框。这时,在ClassView选项卡中,可以看到_DClockEvents接口下又增加了一个方法:NewMinute,并且在CClockCtrl类中增加了一个FireNewMinute方法。这样,在控件内部,就可以调用FireNewMinute方法向容器发出事件通知,而在此方法内部,它会调用_DClockEvents接口中的NewMinute方法向容器发出事件通知。我们发现,在ClockCtrl.h中,自动生成的FireNewMinute方法的代码如下:

   //Event maps //{{AFX_EVENT(CClockCtrl)

   void FireNewMinute()

  {FireEvent(eventidNewMinute,EVENT_PARAM(VTS_NONE));}

   //}}AFX_EVENT

   DECLARE_EVENT_MAP()

  对于上面添加的Click事件来说,因为它是MFC提供的一个标准事件,它的触发过程被底层屏蔽了,所以我们没有看到。而对于自定义的事件来说,必须在某个条件到来时,显式地调用某个函数发出该事件通知。本例中,我们可以在新的一分钟到达时,发出NewMinute事件通知。因此,在CClockCtrl类的OnDraw函数中,在调用GetCurrentTime函数得到系统时间之后,添加下述代码:

  if

  (0==time.GetSecond()) { FireNewMinute();

   }

  也就是说,在得到当前系统时间之后,首先应对秒数进行判断,如果秒数为0,即到达了新的一分钟,就调用FireNewMinute方法,向容器发出NewMinute事件通知。而NewMinute事件是由容器实现的。

  我们通过前面新面的ClockTest程序来测试,打开【ClassWizard】,选择【Message

  Maps】选项卡,选中IDC_CLOCKCTRL1,我们发现它对应一个NewMinute消息,就是我们刚才为Clock控件添加的NewMinute事件。如下图所示:

  单击【Add Function】,弹出如下对话框:

  单击【OK】关闭对话框,并在ClassWizard上单击【EditCode】,为其添加消息响应代码:

   void

  CClockTestDlg:OnNewMinuteClockctrl1() {

   //TODO: Add your control notification handler

  code here

   MessageBox(“New Minute”);

  }

  编译运行程序,我们发现新的一分钟到来的时候会弹出如下消息框:

  这是因为当新的一分钟到来时,Clock控件就会调用FireNewMinute方法,向容器(即ClockTest对话框)发出NewMinute事件,而容器接收到这一事件后,会调用OnNewMinuteClockctrl1来响应。

  同样,也可以用ActiveX Control Test

  Container容器测试该控件。当插入该控件后,可以看到当该控件上显示的时间一旦到达新的一分钟时,该容器下面的窗口中就会显示这样一句话:Clock Control:NewMinute,即触发了一个NewMinute事件。如下图所示:

  到此为止,我们为Clock控件添加了一个标准事件:Click,和一个自定义事件:NewMinute。读者一定要注意,对标准事件来说,其触发过程由MFC底层实现。但对自定义事件来说,必须要在某个条件到来时,在代码中显式地调用某个函数发出该事件通知。

  1.10 ActiveX控件与网页的交互当我们在互联网上畅游的时候,经常会碰到IE浏览器提示我们下载安装某些插件,这些就是所谓的ActiveX插件,那么ActiveX控件是如何嵌入到到网页中的,以及如何与网页通信的呢,这就是本节我们要讲的内容。

  我们用记事本编辑一个html文件,代码如下:

   html

   head

   title 时钟控件测试/title

   meta http-equiv=”Content-Type” content=”text/html;

  charset=gb2312

   meta name=”GENERATOR” content=”Microsoft FrontPage

  4.0

   meta name=”ProgId”

  content=”FrontPage.Editor.Document”

   /head

   script type=”text/javascript”

  language=”javascript”

   !

   function On_PageLoad()

   {

   }

   function Hello_onclick()

   {

   ClockCtrl.Hello();

   }

   /script

   body onLoad=”return On_PageLoad()”

   SCRIPT LANGUAGE=”JScript” EVENT=”NewMinute()”

  FOR=”ClockCtrl”

   alert(“new minute”);

   /SCRIPT

   OBJECT name=”Clock” id=”ClockCtrl” height=”80

  width=”180 classid=”clsid:8377E215-598D-4F31-8BDE-0E16AFF83A9A”

   /OBJECT

   hr/

   INPUT id=”hello” type=”button” value=”执行Hello”

  name=”ButtonStop” return Hello_onclick()”/

   /body

   /html

  下面解释一下这段代码:

   OBJECT name=”Clock”

  id=”ClockCtrl” height=”80 width=”180

  classid=”clsid:8377E215-598D-4F31-8BDE-0E16AFF83A9A”

   /OBJECT

  这段代码表示初始一个

  ActiveX控件对象,前面我们已经讲过ActiveX控件实际上是一个COM组件,他是需要在注册表中注册之后才能使用的,其中clsid:8377E215-598D-4F31-8BDE-0E16AFF83A9A代表在注册表中注册的classid,我们可以打开注册表编辑器,搜索“Clock”,找到Clock在注册表的注册信息,如下图所示:

  实际上,这个classid值也可以在我们的Clock控件程序代码中找到,我们打开Clock.odl文件,在其最下面就可以找到,如下所示:

   //  Class information for

  CClockCtrl

    [

  uuid(8377E215-598D-4F31-8BDE-0E16AFF83A9A),

    helpstring("Clock Control"),

  control ]

    coclass Clock

    {

    [default] dispinterface

  _DClock;

    [default, source]

  dispinterface _DClockEvents;

    };

   SCRIPT LANGUAGE=”JScript” EVENT=”NewMinute()”

  FOR=”ClockCtrl”

  alert(“new minute”);

   /SCRIPT

  这段代码表示网页测试程序去订阅Clock时钟控件暴露出来的事件NewMinute,一旦新的一分钟到来的时候就会弹出如下对话框:

  这样就完成了Clock控件与网页程序的通信。

   INPUT

  id=”hello” type=”button” value=”执行Hello” name=”ButtonStop” return

  Hello_onclick()”/

  这段代码代表单击标题为“执行Hello”的按钮,将执行Hello_onclick()函数:

  function Hello_onclick()

  {

    ClockCtrl.Hello();

  }

  这段代码执行时钟控件暴露出来的方法Hello(),弹出如下对话框:

  这样就完成了网页程序与时钟控件的通信。

  总结:ActiveX控件与网页程序的通信是通过暴露事件,网页程序去订阅该事件,一旦事件发生的条件满足,ActiveX控件就会通知给网页程序,从而实现了ActiveX控件与网页程序的通信。网页程序与ActiveX控件的通信是通过网页程序调用ActiveX控件暴露出来的方法。

  from:http://www.cppcourse.com/activex.html

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: