VC6.0的ActiveX控件实现

时间:2021-03-28 21:02:01

       暑期一个web项目需要用IE浏览器加载ActiveX插件来实现一些类似读卡、写卡的操作。虽然过去一个多月了,貌似以后也不太会再碰到这样的事情,还是想把暑假的工作整理整理,以便以后不时之需。VC6.0的ActiveX控件实现(应该是比较浅显的部分)

      首先, ActiveX控件以前也叫做OLE控件或OCX控件,它是一些软件组件或对象,可以将其插入到WEB网页或其它应用程序中。使用ActiveX插件,可以轻松方便的在 Web页中插入多媒体效果、交互式对象以及复杂程序等等。通常使用C++VB开发ActiveX控件,关于如何做一个ocx控件可以参考孙鑫的书,上面讲得还蛮清楚的。

      这里就简单介绍一下。参考自http://www.cnblogs.com/beer/archive/2010/08/21/1805462.html

1. 建立最简单的ocx文件并进行调试

1.1 建立最简单的ocx文件

    VC->新建项目->MFC ActiveX WinZard

VC6.0的ActiveX控件实现

     一路点击“确定”,直到点击“完成”。最后VC++会自动生成一些文件,这些文件就构成了ActiveX的基本模板,文件的主要结构如下:

VC6.0的ActiveX控件实现

    直接编译一下,然后在Debug目录下面就会生成一个名为“ocxDemo.ocx”的控件注册文件,然后利用“regsvr32”命令就可以实现本机对此控件的注册,然后就可以使用本语言或者跨语言编写程序时引用此控件来实现相应的功能(后面将会讲到)。

1.2 ocx调试方法:

    VC++自带有一个调试控件的工具“ActiveX控件测试容器”,通过三种方式可以打开:

1.点击“调试”按钮,会出现如下对话框:

VC6.0的ActiveX控件实现

     然后浏览"C:\Program Files\Microsoft Visual Studio\Common\Tools\TSTCON32.EXE“

2. 系统的“开始“-》“程序”-》“Microsoft Visual C++ 6.0”-》“Microsoft Visual C++ 6.0 Tools”-》“Active Control Test Container”

3. VC++开发环境中的“工具”-》“ActiveX Control Test Container”

     通过上面的任意一种方法,都可以调出下面的程序:

VC6.0的ActiveX控件实现

     右击空白区域,插入控件,然后会弹出下面的对话框:

VC6.0的ActiveX控件实现

     选中指定控件,然后点击确定,控件就被加载到此工具中了,然后可以通过这个工具来看此控件的相关事件响应等等。

VC6.0的ActiveX控件实现

2.自VC++生成的模板基础上自定义功能

     所有的自定义功能基本上都来自于“MFC ClassWizard”类向导对话框。

    (“快捷键Ctrl+W”或者“查看”->“建立类向导…”)

VC6.0的ActiveX控件实现

     在“Automation”选项卡中为控件添加方法和属性。

     在“ActiveX Events”选项卡中为控件添加事件。

 

2.1 添加控件属性

     切换到“Automation”选项卡中,点击右边的“Add Property…”会弹出对话框:

VC6.0的ActiveX控件实现

External name:外部名称。指此控件被使用时,外部程序看到的属性名称,仅在外部引用时被使用。

Type:属性类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。

Variable name:变量名称。此属性在控件源文件中的变量名称,在编写控件源码时使用。

Notification function:提醒函数。当此属性被改变时,会触发此提醒函数。

Implementation:实现方式。指属性的三种类型:固有型,成员变量型,Get/Set方法型。固有型是指系统赋予的固有属性,如背景色,标题;成员变量型是用户自定义的属性;Get/Set方法型,可能是指只能通过Get/Set方法才能获取和改变的变量吧(这个没研究)。

 

2.2 添加控件方法

     在“Automation”选项卡中,点击右边的“Add Method…”会弹出对话框:

VC6.0的ActiveX控件实现

External name:方法外部名称。

Internal name:方法内部名称。

Return type:返回值类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。

Implementation:实现方式。两种:固有方法,自定义方法。

Parameter list:参数列表。参数名称和参数类型:参数类型包含很多高级数据类型。


2.3 添加控件事件

     切换到“ActiveX Events”选项卡中,点击右边的“Add Event…”会弹出对话框:

VC6.0的ActiveX控件实现

External name:事件外部名称。

Internal name:事件内部名称。比外部名称多了个前缀“Fire”。

Implementation:实现方式。两种:固有事件,自定义事件。固有事件一般是鼠标移动,双击等等事件,这些事件都由系统消息触发;自定义事件则是完全由用户定义的一个函数,但这个函数需要用户在源文件中调用(在内部调用,对于控件的使用方来说,就相当于在调用的地方此事件被触发,而内部传入的参数,则是此事件产生的消息附带信息)。

Parameter list:参数列表。参数名称和参数类型:参数类型包含很多高级数据类型。

     总述:通过“类向导”工具,为控件添加属性、方法和事件后,VC++会自动在相应的文件里面生成代码,比如内部方法属性和外部方法属性之间的映射,消息的建立,消息的声明,等等。如果用户要对引进行深入研究,还需要对程序的结构比较熟悉,知道各部分代码的作用,知道哪些地方的代码是系统自动生成的,哪些代码需要用户手动加入的。Visual C++开发环境虽然有很多优点,但有个缺点也很明显,就是代码结构比较乱,感觉没有VS2005和后面的Visual Studio系列要好。但是由于VC6.0作为一个比较经典的开发环境,而且网上的有关C++的程序设计基本上都是基于VC6.0的,所以,有必要对其进行学习,便于自己读懂网上的代码并进行消化吸收。

 

2.4 生成ocx文件并调试

     直接编译用户加入了自定义代码的项目,然后在项目的Debug目录下面会生成一个ocx文件,这个就是此控件的注册文件了。

     控件的调试工具仍然是“ActiveX Control Test Container”。

     假设我们在控件中加入了一个事件:固有事件——“MouseMove”鼠标移动事件;用户自定义事件——ocxClick事件(此事件是通过“WM_MOUSEMOVE”消息来触发的,返回的是鼠标当前位置的x坐标)。

     运行“ActiveX Control Test Container”并插入当前控件,当鼠标在上面移动的时候,可以看到MouseMove产生了事件了。

VC6.0的ActiveX控件实现

     同时可以通过“Control”-》“Invoke Method”来对控件的方法进行测试,测试的方法就是你输入参数,它返回计算结果(下面以自定义的方法funHello为例)。

VC6.0的ActiveX控件实现

3.控件的使用方法

首先要注册控件,  ocx控件的安装方式有很多种,这里介绍最简单的一种。

步骤:

1.将需要安装的OCX控件文件复制到某个目录,例如C盘根目录下。

2.进入开始,点击运行。

3.在出现的框中键入regsvr32 C:/xxxx.ocx 。(XXXX为控件名, C:/为目录)

4.点击确认后等待出现提醒注册成功即可。

PS:(也可以通过vc6.0里的工具->regester control来注册该控件,但是如果想在客户或者其他机子上安装,上面的方法就很棒了。当然如果您是web项目,自然也是可以通过浏览器来加载改控件)。

      这时如果您运气很棒,就可以在本机使用自己开发的ActiveX控件了。但是此时要是您想在IE中加载您开发的控件就必须实现安全接口,否则浏览器会认为你的控件不安全。

这个可以参考:http://hi.baidu.com/live36524/blog/item/c337bb10432ef703b8127b34.html

      对于OCX形式的Activex最好同时实现IObjectSafety接口,因为否则浏览器可能认为该Activex是不安全的而拒绝加载。

ctrl类的.h的文件中,找到DECLARE_INTERFACE_MAP() ,在其后添加如下代码:

BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)   
 STDMETHOD_(HRESULT,   GetInterfaceSafetyOptions)   (     
                          /*   [in]   */ REFIID   riid,   
                          /*   [out]   */   DWORD   __RPC_FAR   *pdwSupportedOptions,   
                          /*   [out]   */   DWORD   __RPC_FAR   *pdwEnabledOptions   
 );   
                    
    STDMETHOD_(HRESULT,   SetInterfaceSafetyOptions)   (     
                          /*   [in]   */   REFIID   riid,   
                          /*   [in]   */   DWORD   dwOptionSetMask,   
                          /*   [in]   */   DWORD   dwEnabledOptions   
 );   
 END_INTERFACE_PART(ObjSafe);

ctrl类的.cpp中添加如下代码:

BEGIN_INTERFACE_MAP(CWebSealCtrl, COleControl)   
 INTERFACE_PART(CWebSealCtrl, IID_IObjectSafety, ObjSafe)  
 INTERFACE_PART(CWebSealCtrl, IID_IProvideClassInfo, ProvideClassInfo) 
END_INTERFACE_MAP() //此处多个接口要写在一起

ULONG   FAR   EXPORT   CWebSealCtrl::XObjSafe::AddRef()   
{   
          METHOD_PROLOGUE(CWebSealCtrl,ObjSafe)   
          return   pThis->ExternalAddRef();   
}   
    
ULONG   FAR   EXPORT   CWebSealCtrl::XObjSafe::Release()   
{   
          METHOD_PROLOGUE(CWebSealCtrl,   ObjSafe)   
          return   pThis->ExternalRelease();   
}   
    
HRESULT   FAR   EXPORT   CWebSealCtrl::XObjSafe::QueryInterface(   
          REFIID   iid,   void   FAR*   FAR*   ppvObj)   
{   
          METHOD_PROLOGUE(CWebSealCtrl,   ObjSafe)   
          return   (HRESULT)pThis->ExternalQueryInterface(&iid,   ppvObj);   
}   
    
const   DWORD   dwSupportedBits   =     INTERFACESAFE_FOR_UNTRUSTED_CALLER   |   INTERFACESAFE_FOR_UNTRUSTED_DATA;   
const   DWORD   dwNotSupportedBits   =   ~dwSupportedBits;   
    
  /////////////////////////////////////////////////////////////////////////////   
  //   CStopLiteCtrl::XObjSafe::GetInterfaceSafetyOptions   
  //   Allows   container   to   query   what   interfaces   are   safe   for   what.   We're   
  //   optimizing   significantly   by   ignoring   which   interface   the   caller   is   
  //   asking   for.   
HRESULT   STDMETHODCALLTYPE     
CWebSealCtrl::XObjSafe::GetInterfaceSafetyOptions(     
     /*   [in]   */  REFIID   riid,   
     /*   [out]   */  DWORD   __RPC_FAR   *pdwSupportedOptions,   
     /*   [out]   */  DWORD   __RPC_FAR   *pdwEnabledOptions)   
{   
 METHOD_PROLOGUE(CWebSealCtrl,   ObjSafe)   
   
 HRESULT   retval   =   ResultFromScode(S_OK);   
    
 //   does   interface   exist?   
 IUnknown   FAR*   punkInterface;   
 retval   =   pThis->ExternalQueryInterface(&riid,  (void **)&punkInterface);   
 if   (retval   !=   E_NOINTERFACE)   { //   interface   exists   
   punkInterface->Release();   //   release   it--just   checking!   
 }   
    
 //   we   support   both   kinds   of   safety   and   have   always   both   set,   
 //   regardless   of   interface   
 *pdwSupportedOptions   =   *pdwEnabledOptions   =   dwSupportedBits;   
    
 return   retval;   //   E_NOINTERFACE   if   QI   failed   
  }   
    
  /////////////////////////////////////////////////////////////////////////////   
  //   CStopLiteCtrl::XObjSafe::SetInterfaceSafetyOptions   
  //   Since   we're   always   safe,   this   is   a   no-brainer--but   we   do   check   to   make   
  //   sure   the   interface   requested   exists   and   that   the   options   we're   asked   to   
  //   set   exist   and   are   set   on   (we   don't   support   unsafe   mode).   
HRESULT   STDMETHODCALLTYPE     
CWebSealCtrl::XObjSafe::SetInterfaceSafetyOptions(     
                  /*   [in]   */   REFIID   riid,   
                  /*   [in]   */   DWORD   dwOptionSetMask,   
                  /*   [in]   */   DWORD   dwEnabledOptions)   
{   
 METHOD_PROLOGUE(CWebSealCtrl, ObjSafe)   
    
 //   does   interface   exist?   
 IUnknown   FAR*   punkInterface;   
  pThis->ExternalQueryInterface(&riid, (void **)&punkInterface);   
 if   (punkInterface)   { //   interface   exists   
  punkInterface->Release();   //   release   it--just   checking!   
 }   
 else   {   //   interface   doesn't   exist   
  return   ResultFromScode(E_NOINTERFACE);   
 }   
    
 //   can't   set   bits   we   don't   support   
 if   (dwOptionSetMask   &   dwNotSupportedBits)   {     
  return   ResultFromScode(E_FAIL);   
 }   
    
 //   can't   set   bits   we   do   support   to   zero   
 dwEnabledOptions   &=   dwSupportedBits;   
 //   (we   already   know   there   are   no   extra   bits   in   mask   )   
 if   ((dwOptionSetMask&dwEnabledOptions) != dwOptionSetMask)   {   
  return   ResultFromScode(E_FAIL);   
 }   
    
 //   don't   need   to   change   anything   since   we're   always   safe   
 return   ResultFromScode(S_OK);   
}