葡京网投哪个正规 > 首页 > OLE及组件之间的关系,ActiveX控件实现

原标题:OLE及组件之间的关系,ActiveX控件实现

浏览次数:137 时间:2020-03-25

第18课 ActiveX编程(下面X均为ActiveX简称)
1.在VB中调用X控件,添加方法 project->Add components。另外可以用Object Browser来查看控件
2.在VC中创建X控件
   1.新建一个X工程名为Clock,注意一个文件中可以包含多个控件。
   2.保持缺省设置,完成。注意它生成的三个类,以及相关的接口。
   3.运行它。选择TSTCON32.exe作为容器。
   4.选择Insert Control,此时我们可以看到,它画了一个椭圆。也可以在VB中测试。
   5.删除注册信息。用regsvr32 /u +文件名。也可以在菜单选择反注册命令。
   6.重写代码。在CClockCtrl::OnDraw()中画了一个椭圆,此时我们在其中得到系统时间,并显示它。为此我们在OnCreate()设置了一个定时器,每隔一定时间发出一个Invalidate()消息,使窗口重绘。
   7.如何改变控件的背景色和前景色?ClassWizard->AutoMation->Add Property->BackColor,还需要在OnDraw()中加上相应的代码
    CBrush brush(TranslateColor(GetBackColor()));
pdc->FillRect(rcBounds, &brush);
pdc->SetBkMode(TRANSPARENT);
pdc->SetTextColor(TranslateColor(GetForeColor()));
   8.增加属性页。在
   BEGIN_PROPPAGEIDS(CClockCtrl, 2)此时数目也得改成相应的数目
PROPPAGEID(CClockPropPage::guid)
PROPPAGEID(CLSID_CColorPropPage)
   END_PROPPAGEIDS(CClockCtrl)   OK~
   9.增加自定义属性:ClassWizard->AutoMation->Add Property加上一个变量m_interval,类型为short,对应外部变量为Interval。在CClockCtrl中增加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);
}
    10.测试:Control->Invoke Methods
    11.将时间间隔加到属性页中,在资源视图中加入一文本框和编辑框。为EditBox关联成员变量,加入属性interval。
    12.增加方法:ClassWizard->AutoMation->Add Method->Hello加入代码 OK!在VB中可以调用此方法!
    void CClockCtrl::Hello()
{
// TOD Add your dispatch handler code here
MessageBox("Hello world!");
}
    13.增加事件:ClassWizard->AutoMation->Add Events->Click
    14.增加自定义事件:ClassWizard->AutoMation->Add Events->NewMinute
       在新的一分钟到达时发出这个通知,在OnDraw()中写代码:
        CTime time=CTime::GetCurrentTime();
if(0==time.GetSecond())
{
   FireNewMinute();
}
    15.让Interval属性具有持久性。在CClockCtrl::DoPropExchange()中调用PX_short()方法,OK!
     PX_Short(pPX,"Interval",m_interval,1000);
    16.让Property Page和Property属性中的interval保持一致的方法:在OnIntervalChanged()中调用BoundPropertyChanged(0x1);
    17.希望控件在设计时间内不走动的方法:在OnTimer()中, if(AmbientUserMode())InvalidateControl();巧妙!
3.在VC中调用X控件
   1.新建ClockTest对话框应用程序
   2.点击右键->插入X控件->时钟控件
   3.Project->Add Component会生成CClock类。
   4.在CCLockTestDlg中增加CClock类的成员变量m_clock,然后可以动态创建一个这样的东东!
   5.试验Click(),NewMinute(),SetBkColor(),SetForeColor()方法和属性
   6.如何为动态创建的控件做事件响应呢?首先你得知道它的ID号,然后参考非动态的控件事件代码,呵。

1.2 ActiveX控件的好处

在实际编程中,我们可以将常用的功能封装在一个ActiveX控件中,然后将该控件提供给VB或Delphi的开发人员使用。例如,我们开发了一个中国地图控件,正好有一个公司有许多分支机构,如麦当劳,它会不断地在全国各地增加它的加盟店,而麦当劳公司总部需要实时地观测它每月新增的这些加盟店的地理位置。于是麦当劳公司就可以直接购买我们开发的这个地图控件,在地图上显示它们各分支机构的位置,而不需要再自行开发这种控件了。现在很多公司都在做Activex控件的开发,将一些常用功能封装到一个ActiveX控件中,然后提供给其他公司或最终用户直接使用。

 

编写一个 ActiveX 时钟控件

      1.利用 MFC ActiveX ContrlWizard 新建一个 Clock 工程

      2.在新建的工程中有三个类,其中 CClockApp 从 COleControlModule 中派生出来的,

可以将其看作是应用程序类,它的一个实例表示控件程序本身。
 
      COleControl 从 CWnd 派生得到,也是一个窗口类,
      CClockCtrl 相当于单文档程序的主窗口类。
      这个类包含重绘用的 OnDraw 函数,也包含了一些消息映射,包括调度映射。
      Dispatch maps 调度映射,主要是 MFC 提供让外部应用程序可以访问控件的属性和方法。
      Event maps 事件映射,控件向包含它的容器发送事件通知。
 
CClockPropPage 类由 COlePropertyPage 派生而来:
 
      COlePropertyPage
 
      The COlePropertyPage class is used to display the properties of a custom control in a graphical interface, similar to a dialog box. 被用来显示一个自定义控件的属性,类似于一个对话框。它是对话框类,于是 enum { IDD = IDD_PROPPAGE_CLOCK }给它关联了一个对话框资源。
 
      在工程中,还有两个全局函数:STDAPI DllRegisterServer(void);将控件信息写入注册表中 STDAPI DllUnregisterServer(void)卸载注册信息。

      3.在三个类之上,还有类似小勺的图标 Dclock,_DClockEvents,它们表示接口。

      接口是外部程序和控件进行通信的协议,可以把接口看作是函数的集合,外部程序通过接口提供的方法,去访问控件的属性和方法。也可以将接口看作抽象基类,接口中所定义的所有函数都是纯虚函数, 这些函数的实现都是在 CClockCtrl 类中实现,MFC 通过底层的封装使 CClockCtrl 类继承 Dclock 接口。所以调用接口,事实上调用的是 CClockCtrl 类中的函数。由于封装,底层的通信细节我们看不到,如果对这个感兴趣,可以看一些 COM 编程的资料。
 
      4.如果些时编译一下工程,会生成一个 Clock.ocx 文件,它就是 ActiveX 控件的文件。

       要用控件的时候,只需要把这个文件传递给对方。注意:ActiveX 控件不能单独使用,必须嵌入到一个窗口当中一直运行。当我们用 VB 添加控件时,发现了我们刚才编译的控件,但是 VB 怎么知道我们新建的控件的位置呢? 我们发现编译时,输出窗口的最后一行 “Registering ActiveX Control...”说明编译时会注册控件。事实上编译之后,VC 会调用 regsvr32 注册控件,并将信息写入到注册表中,VB 在加载 ActiveX 控件时,会从注册表中搜寻相关的 ActiveX 控件信息。注意:ActiveX 控件在使用之前都需要注册。

      如果想卸载控件,可以在“运行”中输入命令:
      “regsvr32 /u 控件文件完整路径名”,事实上是调用工程中全局函数 DllUnregisterServer 来完成卸载的。
      如果想再次注册控件,可以在“运行”中输入下面命令:
      “regsvr32 控件文件完整路径名”事实上是调用工程中全局函数 DllRegisterServer 来完成注册的。
 
      5.下面实现在控件上输出当时系统时间。

      可以在 OnDraw 函数中完成这个功能。
 
      这样就能做出一个静态的时间控件,如果我们想使控件实时显示时间,需要添加两个消息响应函数  WM_CREATE,WM_TIMER.要使时间可以每秒更新,我们先在 CClockCtrl 类中添加 WM_CREATE 消息处理,在其响应函数 OnCreate()中设置一个计时器:SetTimer(1,1000,NULL);接着增加一个 WM_TIMER 消息响应处理,在 OnTimer 中写上 Invalidate(); 使窗口发生重绘。也可以调用 InvalidateControl()强制控件重绘自身。
 
      6.在 VB 测试中发现,其他很多控件可以修改控件的背景色、前景色和字体颜色,而我们还不行。

      ActiveX 控件有四种属性:
      Stock:为每个控件提供的标准属性,如字体或颜色。
      Ambient:围绕控件的环境属性——已被置入容器的属性。
      这些属性不能被修改,但控件可以使用它们调整自己的属性。
      Extended:这些是由容器处理的属性,一般包括大小和在屏幕上的位置。
      Custom:由控件开发者添加的属性。
 
      7.这时在 VB 测试中,我们的控件也可以修改控件的背景色和前景色了,但是设置完以后没有效果,因为还要 OnDraw 函数中自己编写代码来完成这些改变。要得到控件标准属性,要通过一些函数来完成,如COleControl::GetForeColor 得到前景色,COleControl::GetBackColor 得到背景色,不过要注意的是它们得到的是 OLE_COLOR 的颜色,还需要通过 TranslateColor 方法转换成 COLORREF。
 
      8.控件一般都会有属性页,当我们右键点击控件时会弹出这个属性页方便对控件属性的设置,我们的控件已经有一个属性页,通过 CClockPropPage 类来实现的,显示的面容是对话框资源的内容,下面修改控件属性页:
      属性页之所以可以在窗口中看得到,是因为在 ClockCtl.cpp 中的 BEGIN_PROPPAGEIDS(CClockCtrl, 1)与 END_PROPPAGEIDS(CClockCtrl)之间调用了 PROPPAGEID(CClockPropPage::guid),其中的 guid 表示全局唯一标识符,它是一个128位的整数,用来唯一地标识一个组件或者一个接口。我们可以用 PROPPAGEID 宏增加属性页。
 
      增加颜色属性页
      首先在 BEGIN_PROPPAGEIDS(CClockCtrl, 1)与END_PROPPAGEIDS(CClockCtrl)之间添加代码 PROPPAGEID(CLSID_CColorPropPage)来添加属性页。
 
      CLSID_CColorPropPage 属性表单是控件自身提供的, 我们添加之后不用作任何处理,就可以使用,效果如下:
 
      注意:
      BEGIN_PROPPAGEIDS(CClockCtrl, 2)中的数字2表示有多少个属性页代码要显示,
      如果增加了属性页数字一定要加1,不然如果没有修改或修改错误,会产生不可预料错误。
 
      9.增加一个自定义属性也是通过 MFC ClassWizard 来完成,与第6步增加前景色与背景色的步骤相同。

      1)下面增加设置时间间隔的属性,用这个属性来控件时间刷新频率:
 
      属性添加成功以后,在_DClock 接口中增加了 Interval 属性,同时在 CClockCtrl 类中增加了一个
 成员变量 m_interval 和 OnIntervalChanged()方法(当外部属性修改之后就会调用这个方法)。
 而且它们都在调度映射当中:
 
      2)在 CClockCtrl::OnIntervalChanged()中添加属性处理程序代码
 
      10.使增加的自定义属性在属性表单中设置

      在对话框资源中添加一个编辑框,再为这个编辑框关联一个变量, 注意,我们在为编辑框关联一个变量 m_updateInterval 的同时也关联了一个属性是,这样我们不需要增加代码就能把控件和自定义属性相关联。在 void CClockPropPage::DoDataExchange(CDataExchange* pDX)中会生成下面代码:
 
      这样,我们就可以在属性页里面设置时间间隔了。
 
      11.为控件添加一个方法:

      为控件增加函数,MFC ClassWizard-->Automation-->Add Method Class Name 要选择CClockCtrl 输入函数名,之后就可以在 CClockCtrl 类中找到了。方法添加成功以后,在_DClock 接口中增加了 Hello 方法,同时在 CClockCtrl 类中增加了 Hello 方法。接下来,我们可以在 CClockCtrl 类中增加了 Hello 方法添加自己的代码就可以了。

      12.为控件添加一个标准事件

      我们选择 MFC ClassWizard-->ActiveX Events--->Add Event。事件添加成功以后,会在_DClockEvents 中增加一个事件 Click,DClockEvents 接口是源接口,控件将用这个接口发送通知事件,它不是控件本身实现的接口,这个接口是通过容器来实现的
 
      13.增加一个自定义事件:当秒数为0时,发出一个 NewMinute 事件。

      1)增加一个自定义事件的过程与增加一个标准事件的步骤相同,也可以这样添加在事件接口_DClockEvents 上点击右键,选择增加事件,效果一样,都会弹出 Add Event 对话框。事件添加成功以后,会在_DClockEvents 中增加一个事件NewMinute事件,同时在在 CClockCtrl 类中增加了void FireNewMinute(),也就是在控件内部可以调用 FireNewMinute()向容器发送事件通知,而这个函数内部会调用接口的 void NewMinute()向容器发出事件通知。
 
      2)在 OnDraw()方法添加代码 if(0 == time.GetSecond())FireNewMinute();使当秒数为0时,向容器发出一个 NewMinute 事件通知。标准消息不需要另外写代码向容器发出事件通知,VC在底层代码内部实现了这个过程。

      14.将我们自定义的控件属性在修改之后永久保存下来,用户打开程序之后,控件的属性都是使用原先保存的值。需要在 void CClockCtrl::DoPropExchange(CPropExchange* pPX)加入如下代码 PX_Short(pPX,"Interval",m_interval,1000);之后再在程序中 OnCreate()方法中将 SetTimer(1,1000,NULL); 修改代码为 SetTimer(1,m_interval,NULL);
 
      15.在属性页中修改自定义控件属性的时候,通知容器做相应的调整,从而使容器属性列表中实时地显示我们对属性所作的修改。在 void CClockCtrl::OnIntervalChanged() 中加入如下代码:BoundPropertyChanged(0x1);   //通知容器调度 ID 为1的属性发生了改变
 
      16.前面都是让控件在容器设计时改变控件属性,如果希望用户在设计模式时时钟控件停止运行,而在用户模式下时间会跳动,在控件内部可以通过 AmbientUserMode()方法得到当前控件是处于设计状态还是运行状态。在 void CClockCtrl::OnTimer(UINT nIDEvent)下修改代码如下:
      if(AmbientUserMode())  InvalidateControl();

      17.编写完控件以后,我们可以选择 Win32 Release 方式进行编译,生成发行版 ActiveX 控件。在开发的时候通常是以 Win32 Debug 模式下编译的,这种模式下开发有助于我们开发过程的产生的错误,例如非法内存访问错误;还可以帮助我们调试程序,跟踪程序进而排查错误。但是在调试模式下生成的文件比较大,因为在文件中包含了调试的信息。

      而当我们开发完成后,在 Release 模式下进行编译时,VC

  本文介绍了基于ATL技术以及使用该技术实现了一个简单的圆的控件CircleCtl并且介绍了其在网页中的使用。ActiveX控件作为可重用的代码组件,不仅应用广泛,还可节约开发时间。它将大量的实现细节隐藏起来,以简明的接口与用户名交互,易于使用。对ActiveX技术的研究已经成为当今软件业的热点和潮流。

1.6 时间控件的实现

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

void
CClockCtrl::OnDraw(

 

                     CDC* pdc, const CRect&
rcBounds, const CRect& rcInvalid)

{

       // TODO: Replace the following code with your
own drawing code.

       //pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

       //pdc->Ellipse(rcBounds);

       CTime
time=CTime::GetCurrentTime();

       CString
str=time.Format(“%H:%M:%S”);

       pdc->TextOut(0,0,str);

}

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

在VC++开发环境中,利用Build命令生成Clock控件程序,并运行,如下图所示:

图片 1

可是,这时控件显示的时间是静止的,为了让该时间“动起来”,我们需要设置一个定时器,让它每隔一秒钟发送一个WM_TIMER消息,在响应该定时器的消息处理函数中,让该控件刷新,重新办理出当前系统时间。这里,我们需要在控件窗口创建完成之后设置定时器,为此我们需要为CClockCtrl类增加WM_CREATE消息的处理函数,然后在些函数中,在控件窗口创建完成之后,调用SetTimer函数创建定时器。具体代码如下所示:

int
CClockCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)

 

{

       if (COleControl::OnCreate(lpCreateStruct) ==
-1)

              return -1;

      

       // TODO: Add your specialized creation code
here

      

       SetTimer(1,1000,NULL);

       return 0;

}

接下来,再为CClockCtrl类增加Windows消息:WM_TIMER的处理,在其响应函数OnTimer中调用Invalidate函数,使窗口无效,这样就可以使窗口重绘。具体实现代码如下所示:

void CClockCtrl::OnTimer(UINT nIDEvent)
{

 

       // TODO: Add your message handler code here
and/or call default

       Invalidate();

      
COleControl::OnTimer(nIDEvent);

}

Build并运行Clock控件,将会看到这时这个时钟控件显示的时间随系统当前时间变化而变化了。

孙鑫VC学习笔记:ActiveX 控件

作者:华仔 | 录入时间:2007-12-26 | 点击:313 次    打印此文章) | 字体:大) 中) 小)

基本概念:

容器和服务器程序

      容器应用程序时可以嵌入或链接对象的应用程序。Word 就是容器应用程序。服务器应用程序是创建对象并且当对象被双击时,可以被启动的应用程序。Excel 就是服务器应用程序。ActiveX 控件不能独立运行,它必须被嵌入容器应用程序中,和容器应用程序一起运行。

  ActiveX控件是微软公司提供的功能强大的程序设计和开发技术,是COM组件开发技术的重要组成部分。它是OLE的第三个版本,对原先OLE控件的最大扩展是增加了Internet功能,它不仅可以在支持OLE控件的容器中使用,更可以作为一个Internet控件,直接成为网页的一部分。另外,ActiveX控件作为一种可重用的组件,相当于一个封装好的代码模块,它是通过其方法、属性、事件来与应用程序进行通信的,此外,ActiveX控件是与开发语言无关的。用户在使用控件时不必考虑它是VC还是用VB等其它语言开发的,应用程序都是通过COM与控件进行通信的。可见,任何支持ActiveX控件的软件平台上都可以使用ActiveX控件,它使得不同厂商所开发的控件可以真正地组装在一起,从而令软件的生产过程类似于硬件业的各个插件的装配过程一样,实现了软件的工业化,大大降低了软件的开发成本,极大地提高了软件的生产效率,实现了软件资源的共享。

  • Ø         了解什么是ActiveX控件
  • Ø         掌握如何编写基于MFC的ActiveX控件
  • Ø         掌握如何测试ActiveX控件
  • Ø         掌握如何测试ActiveX控件
  • Ø         了解ActiveX控件如何注册

编译器会在代码生成上、执行速度上做一些优化,同时生成的可执行程序或控件文件会比较小。

在 VC 中编写一个客户端调用 ActiveX 控件:

1.新建一个基于 MFC 对话框的 ClockTest 工程项目

2.点击右键,选择“插入 ActiveX 控件”,然后在弹出的对话框中选择刚才我们创建的控件。

也可以通过菜单的方式增加控件:
 “工程”->增加到工程->Componets and Controls
 选择已注册控件"Registered ActiveX Contrlos",找到我们自己控件,再按下插入。
 
通过这种方式插入 ActiveX 控件时,会在工程中自动生成一个类 CCock,其基类为 CWnd。这个类是一个封装类,封装了对 ActiveX 控件进行访问的一些操作。同时在 VC 的工具箱上面也增加一个时钟控件,可以直接将一个时钟控件拖放到窗体上。

3.用第二种方法插入的控件,除了将控件手动插入到窗体以外,我们也可以通过代码动态生成一个控件。

1)CClockTestDlg 增加一个成员变量:CClock m_clock;
2)在 CClockTestDlg 的头文件中包含一个 clock.h
3)接下来就要以在一个按钮的单击事件中增加创建控件的代码:
4)在设计时,可以点击右键为控件添加事件响应。

图片 2

图片 3

  2) 向ATL项目添加ActiveX控件

本章目标:

基于VC++中ATL创建ActiveX控件的探讨

1.8 方法

下面,为Clock控件添加一个自定义的方法。同样,这也是利用ClassWizard来完成的。首先打开ClassWizard对话框,选择Automation选项卡,注意:在此属性页上,class name这一选项一定要选择CClockCtrl。然后,【Add
Method】按钮,这时将出现如下对话框:

图片 4

该对话框中提供了几个选项,其中外部名称(External
name)是给外部程序使用控件的方法时使用的,这里,我们可以将其设置为Hello。读者可以看到,系统自动为该方法提供了一个内部名称(Internal name):Hello,这个内部名称是在控件内部使用的方法名称,它可以与外部名称不一样。然后将返回类型(Return type)设置为void,不用给这个方法设置参数。如下所示:

图片 5

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

void CClockCtrl::Hello()

 

{

       // TODO: Add your dispatch handler code
here

       MessageBox(“Hello world!”);

}

利用Build命令生成最新的Clock控件,再次利用ActiveX Control Test
Container容器测试该控件。在该容器中调用控件方法的步骤是:选中Clock控件,选择【ControlInvoke
Methods…】菜单项,这时将打开Invoke Methods对话框,在此对话框的Method
Name下拉列表框中选择“Hello”方法,然后单击【Invoke】按钮,就会调用Clock控件的Hello方法,将出现如下图所示的消息框:

图片 6

  首先,在CCircleCtl的构造函数中对绘制圆的填充色进行初始化,将它的初始值设为红色,即m_clrFillColor=RGB(255,0, 0)。

本文源码与文档下载

  ATL是ActiveX Template Library 的缩写,它是一套C++模板库。使用ATL能够快速地开发出高效、简洁的代码(Effective and Slim code),同时对COM组件的开发提供最大限度的代码自动生成以及可视化支持。从Microsoft Visual C++ 5.0版本开始,Microsoft把ATL集成到Visual C++开发环境中。目前,ATL已经成为Microsoft标准开发工具中的一个重要成员,日益受到C++开发人员的重视。

1.1 什么是ActiveX控件

Activex控件是微软提供的功能强大的程序设计和开发技术。ActiveX是基于OLE和COM的一门开发技术,它既是一个自动化对象,也是一个COM对象。根据微软权威的软件开发指南MSDN(Microsoft Developer
Network)的定义,ActiveX控件以前也叫做OLE控件或OCX控件,它是一些软件组件或对象,可以将其插入到WEB网页或其它应用程序中。在形态上ActiveX控件是后缀名为ocx的控件,但是,读者应该注意的是,Activex控件对应的文件也可以是其他后缀名,如.dll。

一个典型的ActiveX控件,它具有方法、属性、事件这三种特性。

  (1)创建一个新的ATL工程,并对工程的选项进行适当的配置。

本章将介绍ActiveX控件的应用与工作原理。我们可以把ActiveX控件看做是一个极小的服务器应用程序,它不能独立运行,必须嵌入到某个容器程序中,与该容器一起运行。那么,该容器就相当于客户程序,它使用ActiveX提供的服务。

  2) ATL的基本使用

1.7.1   标准属性

在VC++开发环境中,如果想要为控件添加属性,可以通过ClassWizard来完成。首先打开ClassWizard对话框,然后选择Automation选项卡,接着单击该选项卡上的【Add
Property…】按钮,将出现如下图所示的添加属性对话框:

图片 7

在此对话框上,单击External
name(外部名称)下拉列表框,将会看到在出现的列表框中有许多属性,这些都是MFC为ActiveX控件提供的标准属性,其中就有BackColor(背景色)和ForeColor(前景色)属性,如果想要为控件添加某种标准属性,只要从该列表中选择该属性,例如选择BackColor,并保持默认的Stock选项选中状态,单击【OK】按钮即为控件添加了背景色属性。然后按照同样的方法为Clock控件添加ForeColor属性。这时,Clock控件的Automation选项卡内容如下图所示:

图片 8

可以看到,新添加的这两个属前面都有一个“S”标志,而且下面的提示说明它们是一个“Stock Property”,即常规的,或储备的属性。在ActiveX控件中有四种属性。

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

l         Ambient:围绕控件的环境属性——已被置入容器的属性。这些属性不能被更改,但控件可以使用它们调整自己的属性。

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

l         Custom:由控件开发者添加的属性。

单击上图所示对话框上的【OK】按钮关闭ClassWizard对话框,然后,在VC++开发环境中的Class View选项上的_DClock接口下,可以看到添加了两个属性:BackColor和ForeColor。

再次利用Build命令生成Clock控件。

  1)ATL

注:本文改编自孙鑫教程,在此基础上加入了Active控制与网页的交互。

  现在来添加Circle控件的一个基本属性——Radius。

1.9 事件

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

  在控件生成时,系统同时生成了一个CircleCtl.htm文件,在VC编辑环境下打开该文件,在和之间加上如下的VBScript:

1.3 用MFC编写基本的ActiveX控件

下面,我们利用VC++编写一个ActiveX控件,这可以利用MFC ActiveX
ControlWizard为我

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

本例将开发一个时钟控件。在VC++开发环境中,选择【FileNew】菜单项,在打开的对话框上选择Projects选项卡,并在列表框中选择MFC
ActiveX ControlWizard,工程名设置为:Clock。单击【OK】按钮,进入MFC ActiveX
ControlWizard向导的第一步,如下图所示:

图片 9

这里,第一个选项的作用是询问用户该工程中将要提供的控件数目。注:一个文件中可以包含多个ActiveX控件。本例中,我们对以上选项都选择默认。

单击【Next】按钮,进入MFC ActiveX
ControlWizard向导的第二步,如下图所示。

图片 10

单击【Finish】,就创建了一个MFC ActiveX控件工程。我们可以看到,MFC
ActiveX ControlWizard向导创建的工程自动生成了三个类,如下图所示:

图片 11

其中CClockApp类派生于COleControlModule类,而后者的派生层次见下图

图片 12

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

CClockCtrl类派生于COleControl类,后者的派生层次结构如下图所示:

图片 13

可以看到,COleControl类是从CWnd类派生的,因此,它也是一个窗口类,相当于单文档应用程序中的主窗口类,或者视类,那么对控件窗口进行的操作都将在CClockCtrl类中完成。在该类中,可以看到它提供了一个OnDraw函数,当控件窗口发生重绘时就会调用这个函数。如果控件需要输出图形,就可以在这个函数中编写相应的实代码。

我们先来看看CClockCtrl类头文件中的部分内容:

// Message
maps

 

       //{{AFX_MSG(CClockCtrl)

              // NOTE – ClassWizard will add and remove
member functions here.

              //    DO NOT EDIT what you see in these
blocks of generated code !

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

//
Dispatch maps

       //{{AFX_DISPATCH(CClockCtrl)

              // NOTE – ClassWizard will add and remove
member functions here.

              //    DO NOT EDIT what you see in these
blocks of generated code !

       //}}AFX_DISPATCH

       DECLARE_DISPATCH_MAP()

       afx_msg void AboutBox();

//
Event maps

       //{{AFX_EVENT(CClockCtrl)

              // NOTE – ClassWizard will add and remove
member functions here.

              //    DO NOT EDIT what you see in these
blocks of generated code !

       //}}AFX_EVENT

      
DECLARE_EVENT_MAP()

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

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

图片 14

可以看到,COlePropertyPage类派生于CDialog类,它以一种类似于对话框的图形界面显示一个自定义控件的属性。也就是说,CClockPropPage类是用来显示Clock控件的属性页的。

另外,读者可以看到在该工程中还有两项内容:_DClock和_DClockEvents,之母们的前面都有一个像平放着小勺一样的图标(图片 15),该图标表示对应的项是接口,接口是控件与外部程序进行通信的协议。可以把接口看作是函数的集合,外部程序通过这个接口所暴露出来的方法去访问控件的属性和方法。实际上,可以把接口看作是一个抽象基类,在此接口中定义的所有函数都是纯虚函数,这些函数的实现是在CClockCtrl类中完成的。MFC通过底层的封装,让CClockCtrl类继承自接口:_DClock,所以通过该接口调用的函数实际上是调用CClockCtrl类中真正实现的函数。ActiveX控件中的接口与计算机机硬件的接口是类似的,例如,在计算机硬件中,主板与显卡间的通信是通过主板上的插槽完成的,这个插槽就是主板与显卡进行通信的接口,一旦我们制定了这个接口,就可以任意地选择一块主板与一块显卡进行通信。因为该接口是标准的,所以选择任一厂商生产的主板,任一厂商生产的显示都是可以的,只要它们的接口遵从共同的标准。主板通过该接口所暴露出来的方法去调用显卡的显示功能,而显卡需要实现该接口所暴露出来的方法。显卡就相当于这里的ActiveX控件,而主板就相当于与控件通信的外部容器。如果两个通信实体要通过接口进行通信,那么肯定是其中的一个实体实现该接口所暴露出来的方法,而另一个实体通过接口调用这些方法。这里,就是ActiveX控件实现接口所暴露出来的方法,而容器调用这些方法。关于接口的底层实现,需要了解一些COM的基本知识,读者如感兴趣的话,可自行查看相关资料。本例中,因为MFC提供的封装,所以底层的细节是看不到的。

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

  (4)编译连接工程,注册COM应用。
  利用ATL技术创建ActiveX控件CircleCtl

1.5 ActiveX控件的注册

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

图片 16

我们看到Registering ActiveX
Control…,表明在生成Clock控件程序时,VC++环境已经帮我们注册了该控件。实际上,VC++是编译器是通过调用regsvr32程序去完成这个操作的。

如果想要删除ActiveX控件的注册信息,可以利用Regsvr32程序的/u选项来实现。我们可以选择系统的【开始运行】命令,然后在对话框上的打开编辑框控件中输入regsvr32
/u,再在其后输入想要删除的ActiveX控件的完整路径,如下图所示。

图片 17

单击【确定】按钮,这时会弹出如下所示的信息对话框:

图片 18

该信息框中提示“DllUnregisterServer in
D:CodeClockDebugClock.ocx succeeded”。这里DllUnregisteredServer是一个函数,并且是ActiveX控件提供的一个函数。“regsvr32 /u”这一命令执行是实际上调用的是指定控件的DllUnregisterServer函数来删除控件的注册信息,因为对于regsvr32程序来说,它并不知道需要删除哪些信息,所以它只是调用控件的DllUnregisterServer函数,由后者来删除该控件在注册表中的注册信息。

当删除了Clock控件在注册表中的信息之后,如果在ActiveX Control Test
Container程序中再想加载Clock控件时,在控件列表中就找不到这个控件了。

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

图片 19

在该信息框中提示:“DllRegisterServer in
D:CodeClockDebugClock.ocx succeeded”。同样的,DllRegisterServer也是ActiveX控件提供的一个函数。当执行regsvr32这一命令时,它实际上是调用指定控件的DllRegisterServer函数,将该控件的信息写入注册表。因此,实际上,ActiveX控件的注册和取消注册都是利用该控件自身提供的两个函数来完成的,regsvr32程序只是调用这两个函数而已。当注册完成后,在ActiveX Control Test
Container程序的控件列表中就可以找到Clock控件了。

  现在将向ATL控件中添加Click和RClick事件。如果用户在矩形区内点击,则会激发相应事件。现在要向ICircleCtlEvents接口添加Click方法,首先在“ClassView”中选中“ICircleCtlEvents”右击,选择Add Method,出现如下对话框,并按下图设置,最后点“OK”按钮就可以添加Click事件的实现方法。用同样的方法添加RClick事件,参数与Click事件一致。接下来我们要为控件实现连接点接口IConnectionPoint和连接点容器接口IConnectionPointContainer。编译好Circle.idl文件,生成对应的Circle.tlb,在“ClassView”中选中“CCircleCtl”,右击,在Popup菜单中选择“Implement Connection Point”命令,在弹出的对话框中选中“_ICircleCtlEvents”接口。在类中定义了以两个坐标为参数的Fire_Click和Fire_RClick方法,调用这两个方法就可以在控件中激发响应的事件。

1.7 属性

读者可以发现,在VB中提供了一个如下图所示的属性面板,通过此面板,可以修改控件属性的值。该面板的左边列出了控件的一些属性,对Clock控件来说,当前我们没有为它添加任一属性,都是MFC ActiveX
ControlWizard自动生成的属性;面板的右边就是属性对应的值,例如,控件的Name(名称)属性是Clock1。如果我们想要改变Clock控件的前景色和背景色,却发现Clock控件的前景色和背景色,却发现在Clock控件的属性面板中没有看到前景色和背景色这两种属性。但是如果在VB程序的窗体上放置一个列表框控件,然后在属性面板上就可以看到该控件有BackColor(背景色)和ForeColor(前景色)属性,可以用来设置该控件的背景色和前景色。如果希望为Clock控件也提供这样的属性,让用户可以设置该控件的前景色和背景色,那么就需要在VC++开发环境中继续完善Clock控件,为它添加这样的属性。

图片 20

  结束语

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” onClick=”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在注册表的注册信息,如下图所示:

图片 21

实际上,这个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,一旦新的一分钟到来的时候就会弹出如下对话框:

图片 22

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

<INPUT
id=”hello” type=”button” value=”执行Hello” name=”ButtonStop” onClick=”return
Hello_onclick()”/>

 

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

 

function Hello_onclick()

{

    ClockCtrl.Hello();

}

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

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

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

from:

  引言

1.7.2   自定义属性

当前Clock控件是每隔1秒更新一次时间的显示,接下,我们给Clock控件增加一个自定义的属性:时间间隔,在用户设置了该属性的值以后,Clock控件就按照用户指定的时间间隔值来更新显示的时间。

这时同样需要利用ClassWizard来了Clock控件添加属性,并且也是选择ClassWizard对话框上的Automation选项卡,然后单击【Add
Property】按钮,将弹出增加属性对话框。在该对话框中有几项内容,其中External
name(外部名称)是在像VB这样的集成开发环境中所看到的控件属性名称,而Variable
name(变量名称)是在VC++集成开发环境中开发这个控件时使用的该控件类的成员变量。也就是说,在开发程序中使用Variable
name访问控件属性,而在外部使用该控件时,使用的是External
name访问控件的属性。这里,我们将新添加的时间间隔属性的外部名称设置为Inverval,类型选择为short类型,变量名称自动被设置为m_interval,ClassWizard为该控件自动增加了一个通知函数:OnIntervalChanged(如下图所示),当在外部修改该属性时,这个函数将被调用。

可以看到,在添加属性对话框上为我们提供了三个单选按钮,但这时只有两个选项可供选择,默认选择的是Member variable,当选择该选项后,ClassWizard会为该属性生成一个成员变量,并生成一个通知函数,正如上图所示的那样;如果选择Get/Set
methods选项,这时添加属性对话框就变成了下图所示的样子。可以看到,这时在添加属性对话框中就没有成员变量和通知函数这两个选项了,ClassWizard会为该属性自动生成两个函数:SetInterval和GetInterval。在程序中,如果想要设置Interval属性的值,可以调用SetInterval函数;如果想要得到该属性的值,可以调用GetInterval函数。但在控件内部,如果想要保存Interval这个属性的值,需要我们自已定义一个成员变量来实现。刚才我们已经看到,如果选择Member variable选项,ClassWizard会自动生成一个这样的成员变量,本例保持默认设置,即选择Member variable选项。

图片 23

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

void
CClockCtrl::OnIntervalChanged()

 

{

       // TODO: Add notification handler
code

       SetModifiedFlag();

}

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

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

// Dispatch maps

 

       //{{AFX_DISPATCH(CClockCtrl)

       short m_interval;

       afx_msg void
OnIntervalChanged();

       //}}AFX_DISPATCH

       DECLARE_DISPATCH_MAP()

可以看到,增加的m_interval和OnIntervalChanged函数的定义都位于CClockCtrl类的调度映射中。前面已经介绍过,调度映射主要是为了让外部应用程序可以方便地访问控件的属性和方法。

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

void
CClockCtrl::OnIntervalChanged()

 

{

       // TODO: Add notification handler
code

       if
(m_interval<0||m_interval>6000)

       {

              m_interval=1000;

       }

       else

       {

             
m_interval=m_interval/1000*1000;

       }

       KillTimer(1);

       SetTimer(1,m_interval,NULL);

       SetModifiedFlag();

}

因为时间间隔不能为负数,也不能太大。所以在OnIntervalChanged函数中,首先对m_interval变量的值进行判断,如果用户设置的时间间隔属性值小于0,或者大于6000,则就将这个间隔值设置为1000。否则,进行调整,即对用户输入的值取整,得到一个整数的秒数。接下来,调用KillTimer函数销毁先前设置的定时器(其标识是1),时间间隔用Clock控件的m_interval属性值来设置。

利用Build命令生成最新的Clock控件,然后利用ActiveX Control Test
Container容器测试该控件。在利用【EditInsert New
Control…】命令插入该控件后,为了测试控件的属性,需要选中该控件,然后单击【ControlInvoke
Methods…】菜单项,这时将显示如下的对话框:

图片 24

在此对话框中有一个方法名称(Method
Name)下拉列表,在此列表中列出了当前控件提供的方法,如下图所示:

图片 25

如果想要得到某个属性值,应该选择PropGet类型的方法:如果想要设置某个属性的值,则应该选择PropPut类型的方法。这里我们想要设置Clock控件的Interval属性的值,因此应该选择Interval(PropPut)项,并在随后出现的对话框的Parameter编辑框中输入数值:2000,单击【Set
Value】按钮,这时就把Interval属性的值设置为2000了,如下图所示

图片 26

但是,这时这个属性值仍未生效,需要单击【Invoke】按钮才行。之后就会发现Clock控件显示的时间每隔2秒跳动一次,说明设置生效了。

  关键词 ATL,ActiveX控件,事件

完成本章学习后,您将能够:

<SCRIPT LANGUAGE="VBScript">
<!--
Sub CircleCtl_Click(x, y)
 If CircleCtl.Radius <100 Then
  CircleCtl.Radius = CircleCtl.Radius+1 ‘半径加1
 Else
  MsgBox(“Radius must be less than 100!”)
 End If
End Sub
Sub CircleCtl_RClick(x, y)
 If CircleCtl.Radius >=1 Then
  CircleCtl.Radius = CircleCtl.Radius-1 ‘半径减1
 Else
  MsgBox(“Radius mustn’t be less than 0!”)
 End If
End Sub
-->
</SCRIPT>

1.9.1   标准事件

在VC++中,如果想要为Clock控件添加一个事件,可以利用ClassWizard来完成。首先打开ClassWizard对话框,并打开它的ActiveX Events选项卡,在此选项卡上,确保Class name组合框中选择的是CClockCtrl。然后单击【Add
Event】按钮,将显示添加事件对话框,在此对话框上有一个名称为External
name的组合框,当单击其右边向下的箭头时,将会看到该列表框中列出了一些预先准备好的事件(如下图所示),即MFC提供的一些标准的事件,例如Click事件。这里,我们先为Clock控件增加一个标准事件,也就是一个Stock事件。在External
name下拉列表中选择Click,保持默认的Stock选项不变,然后单击【OK】按钮关闭Add
Event对话框,并单击ClassWizard对话框上的【OK】按钮,关闭该对话框。

图片 27

这时,在ClassView选项卡中可以看到,在_DClockEvents接口下面增加了一个方法:Click,该方法就是刚刚添加的Click事件。为什么添加的事件增加到_DClockEvents接口中,而没有放到_DClock接口中呢?读者可以在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;

       };

在上述所示的代码中,可以看到在说明_DClockEvents接口时,其前面有一个“source”标识,而_DClock接口前面并没有此标识。“source”标识表明_DClockEvents接口是一个源接口。源接口表示控件将使用这个接口来发送通知事件,这个接口不是控件本身实现的接口。前面已经提过,作为利用接口进行通信的双方,肯定是一方调用接口所暴露出来的方法,另一方实现该接口所提供的方法。我们现在所实现的Clock控件正是调用_DClockEvents接口提供的方法,向容器发出事件通知。既然是控件使用_DClockEvents接口提供的方法,那么谁负责实现这个方法呢?实际上,_DClockEvents接口中的方法是由容器实现的。容器通过一种机制知道控件中定义了一个源接口,于是它就实现该接口。这里,读者可能会有这样的疑问,为什么容器实现的接口由控件定义呢。一方面,对于每个控件来说,它可以有自己的事件接口,而容器是无法预先知道控件将使用哪一个事件接口发出通知,因此我们在编写控件的同时指定事件接口,并将其标识为源接口。另一方面,接口由谁来定义是无所谓的,例如,主板与显卡进行通信,那么是主板厂商去定义接口,还是由显卡产商去定义接口,或者它们一起来定义接口,这都是一样的,关键是通信的双方能够遵照一个接口进行通信就可以了。

现在,我们已经为Clock控件增加了一个标准事件:Click,再次利用ActiveX Control Test
Container容器测试该控件。当插入Clock控件后,在此控件上单击鼠标左键,这时,在该容器下面的窗口中可以看到这样一句话:Clock Control:Click,即触发了Clock控件的Click事件,如下图所示:

图片 28

我们也可以用前面新建的VC++工程ClockTest来测试,打开【ClassWizard】,选择【Message
Maps】选项卡,选中IDC_CLOCKCTRL1,我们发现它对应一个Click消息,就是我们刚才为Clock控件添加的Click事件。如下图所示:

图片 29

点击【Add Function…】,为其添加一个消息处理,如下所示:

图片 30

点击【OK】关闭对话框,再点击ClassWizard上的【Edit Code】按钮,添加消息响应代码:

void
CClockTestDlg::OnClickClockctrl1()

 

{

       // TODO: Add your control notification handler
code here

       MessageBox(“Clock Clicked”);

}

编译运行该程序,我们在Clock控件上单击鼠标左键,弹出如下消息框:

图片 31

这是因为当在Clock控件上单击鼠标左键时,该控件接收到该单击消息,于是它就利用_DClockEvents接口中的方法(即Click方法)向容器(即ClockTest对话框)发出事件通知,因为_DClockEvents这个源接口是容器实现的,相当于控件调用了容器的Click方法,实际上就是调用了OnClickClockctrl1这个消息响应函数中的代码。

  // 创建画笔和画刷并选中颜色画圆

  hPen = (HPEN)GetStockObject(BLACK_PEN);

  hOldPen = (HPEN)SelectObject(hdc, hPen);

  hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);

  hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);

  hBrush = CreateSolidBrush(colFore);

  SelectObject(hdc, hBrush);

  Ellipse (hdc, (CenterPt.x - m_radius), (CenterPt.y - m_radius), (CenterPt.x +m_radius),(CenterPt.y+ m_radius));

1.9.2   自定义事件

在VC++中,为了给ActiveX控件增加自定义事件,同样可以利用ClassWizard来完成,与上面添加标准事件的过程是一样的。另外,也可以在工程的ClassView选项卡上,用鼠标右键单击_DClockEvents接口,并从弹出的快捷菜单中选择【Add
Event…】菜单项,从而也可以打开添加事件对话框。利用该对话框,我们为Clock控件添加一个自定义的事件,新添加的这个事件的外部名称设置为:NewMinute,系统将自动将该事件的内部名称设置为:FireNewMinute,结果如下所示:

图片 32

单击【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事件。如下图所示:

图片 33

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

图片 34

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

void
CClockTestDlg::OnNewMinuteClockctrl1()

 

{

       // TODO: Add your control notification handler
code here

       MessageBox(“New Minute”);

}

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

图片 35

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

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

图片 36

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

  在ATL产生以前,开发COM组件的方法主要有两种:一是使用COM SDK直接开发COM组件,另一种方式是通过MFC提供的COM支持来实现。

重点:ActiveX控件的实现、测试及注册。

  注意保存。然后在“我的电脑”中打开该htm文件,用鼠标单击圆,半径变大,右击圆半径变小。

1.4 ActiveX控件的测试

我们在VC++开发环境中运行Clock程序,将出现如下对话框,让用户选择一个可执行程序。

图片 37

前面已经提到,ActiveX控件不能独立运行,它必须嵌入到一个容中运行。因此,我们可以点击该对话框上标示了一个向右箭头的按钮,将弹出如下的快捷菜单。

图片 38

可以选择【ActiveX Control Test
Container】菜单项,也就是说,我们选择ActiveX
Control Test Container这个应用程序作为Clock控件的容器,该应用程序位于Microsoft Visual Studio安装目录下的CommaonTools子目录下,程序名称为:TSTCON32.EXE。如果没有出现这个应用程序所对应的菜单项,那么可以选择【Browse】菜单项,然后找到TSTCON32.EXE程序并选中即可。

最后,单击【OK】按钮,这时将打开ActiveX Control Test
Container应用程序,如下图

图片 39

于是我们就可以加载特定的ActiveX控件,方法是选择【EditInsert New
Control…】菜单项,这时将弹出如下对话框

图片 40

然后在该对话框左边的列任意选中一个控件,接着快速连续地按下键盘上的【C】、【L】、【O】键,就可以直接定位到我们刚刚生成的Clock控件。

图片 41

然后单击对话框上的【OK】按钮关闭该对话框,这时,在ActiveX Control Test
Container应用程序中就加载了Clock控件,这个ActiveX控件当前的功能就是绘制一个椭圆,如下图所示:

图片 42

当然,我们也可以新建一个VC++对话框工程来进行测试,该工程取名为ClockTest。如果想要在对话框资源上添加一个ActiveX控件,方法是:在对话框资源上单击鼠标右键,从弹出的快捷菜单中选择【Insert
ActiveX
Control…】菜单项,这时将显示如下对话框,在此对话框中找到Clock控件并选中,然后单击【OK】按钮关闭该对话框即可。

图片 43

这时,在对话框资源上就插入了Clock控件。

在VC++中,另一种插入ActiveX控件的方法是,选择【ProjectAdd to
ProjectComponets and Controls…】菜单项,将显示如下对话框:

图片 44

在此对话框中,双击“Registered ActiveX
Controls”目录,并在此目录下找到Clock控件并选中,如下所示:

然后单击【Insert】按钮,并单击随后显示的确认对话框上的的【确定】按钮,这时图片 45将弹出如下对话框:

图片 46

当通过这种方法插入ActiveX控件时,会在工程中为该控件生成一个类,这里就为Clock控件生成了一个类,类名为CClock,其基类是CWnd。该类是控件的封装类。它封装了对这个ActiveX控件进行访问的一些操作。单击【OK】按钮关闭该对话框,这时,在ClockTest工程的ClassView选项卡上,可以看到增加了一个类:CClock,该类提供了一些函数,我们只需要调用这些函数就可以访问Clock这个ActiveX控件的方法和属性。同时,在工具箱上也增加了Clock控件的图标,如下图所示:

图片 47

我们只需要单击该图标,就可以在对话框资源上拖放一块合适的区域放置一个Clock控件。如下图:

图片 48

摘 要 介绍了ActiveX控件和ATL技术,并以一个简单的圆的控件实现为例,介绍了VC++6.0中如何用ATL技术创建ActiveX控件,以及如何在网页中使用该控件。

  (2)向新创建的工程添加新的ATL类,并对该类进行一些初始配置工作。

  在Workspace Windows中Class View状态下,右击 ICircleCtl接口,选择Add Property,属性类型为short,名为Radius,参数为空。系统会自动生成get_Radius和put_Radius两个成员函数。在CCircleCtl中添加m_radius变量,用来存储半径。在CCircleCtl的构造函数中将其初始化为50,并在get_Radius函数中添加*pVal=m_radius; 在put_Radius函数中添加m_radius=newVal; FireViewChange();用来及时更新视图。对于Radius的属性,我们通过修改控件的绘制代码来使它起作用。

  5) 为ActiveX控件添加事件

  ATL技术是目前开发COM组件的一种比较理想的技术。ATL中所使用的基本技术包括COM技术、C++模板类技术(Template)以及C++多继承技术(Multi-Inheritance) 。

  使用MFC提供的COM支持开发COM应用可以说在使用COM SDK基础上提高了自动化程度,缩短了开发时间。MFC采用面向对象的方式将COM的基本功能封装在若干MFC的C++类中,开发者通过继承这些类得到COM支持功能。但使用MFC开发的COM组件,尤其是ActiveX控件的开发,会产生相当大的代码冗余,而且必须要依赖于MFC的运行时刻库才能正确地运行。

  1) 创建ATL项目

  最后,添加激发事件的代码,我们分别在鼠标左键和右键按下的消息响应中进行处理,激发响应的事件,例如OnLButtonDown函数部分代码如下:

  首先从Insert菜单项中选择New ATL Object…调出 ATL Object Wizard对话框,然后左边Category列表选择Object,右边相应地选择Full Control,如图(1)所示。按Next继续,出现 ATL Object Wizard属性对话框,如图(2),在Names选项卡中,我们只需要在Short Name 编辑框输入CircleCtl即可,其它系统就会自动给定,也可以修改,我们这里保持系统给定状态;在Attributes 选项卡中,选择 Support ISupportErrorInfo 和 Support Connection Points 两个复选框,这两项分别支持出错信息和连接点;Miscellaneous选项卡保持默认设置;Stock Properties中我们把FillColor添加到支栏中,确定之后就把该控件加到项目中了。

  使用ATL COM AppWizard 创建ATL框架为该项目命名为Circle,按照向导提示向下做,采用默认设置,即Server Type类型为Dynamic Link Library(DLL)。

  WORD xPos = LOWORD(lParam); //鼠标水平坐标
  WORD yPos = HIWORD(lParam); // 鼠标垂直坐标
  Fire_Click (xPos, yPos); //执行触发函数

  然后修改OnDraw函数,在该绘制函数中,使用 Windows API中标准的HDC、HPEN、HBRUSH以及SelectObject、Ellipse等结构和函数来实现绘制的。例如:

  ATL技术

  使用ATL开发一个COM应用基本可以分为以下几个步骤:

  图1 图2

  4) 修改ActiveX控件的绘制代码实现属性交换

  图片 49 图片 50

  (3)根据COM应用的基本要求向新的ATL类加入新的接口定义,并实现相应的接口成员函数。

  static POINT CenterPt;
  static long RectHt = 0;
  static long RectWd = 0;

作者: 任凤华 李兰 出处: 计算机遇信息技术

  网页中使用ActiveX控件

  3)为ActiveX控件添加自定义属性

  至此,可以在ActiveX Control Test Container中测试该控件。

  接下来,我们需要几个全局变量来保存控件区域的信息,在CircleCtl.h中添加如下变量:

  直接使用COM SDK开发COM组件是最基本也是最灵活的方式。但是,这种开发方式的难度和工作量都很大,一方面,要求开发者对于COM的技术原理具有比较深入的了解,另一方面,直接使用COM SDK要求开发人员自己去实现COM应用的每一个细节,完成大量的重复性工作。

本文由葡京网投哪个正规发布于首页,转载请注明出处:OLE及组件之间的关系,ActiveX控件实现

关键词:

上一篇:VC视频教程笔记,MFC文件操作

下一篇:TCP小聊天具体代码实现,基于TCP的程序设计和基于UDP的程序设计