暑期一个web项目需要用IE浏览器加载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
一路点击“确定”,直到点击“完成”。最后VC++会自动生成一些文件,这些文件就构成了ActiveX的基本模板,文件的主要结构如下:
直接编译一下,然后在Debug目录下面就会生成一个名为“ocxDemo.ocx”的控件注册文件,然后利用“regsvr32”命令就可以实现本机对此控件的注册,然后就可以使用本语言或者跨语言编写程序时引用此控件来实现相应的功能(后面将会讲到)。
1.2 ocx调试方法:
VC++自带有一个调试控件的工具“ActiveX控件测试容器”,通过三种方式可以打开:
1.点击“调试”按钮,会出现如下对话框:
然后浏览"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”
通过上面的任意一种方法,都可以调出下面的程序:
右击空白区域,插入控件,然后会弹出下面的对话框:
选中指定控件,然后点击确定,控件就被加载到此工具中了,然后可以通过这个工具来看此控件的相关事件响应等等。
2.自VC++生成的模板基础上自定义功能
所有的自定义功能基本上都来自于“MFC ClassWizard”类向导对话框。
(“快捷键Ctrl+W”或者“查看”->“建立类向导…”)
在“Automation”选项卡中为控件添加方法和属性。
在“ActiveX Events”选项卡中为控件添加事件。
2.1 添加控件属性
切换到“Automation”选项卡中,点击右边的“Add Property…”会弹出对话框:
External name:外部名称。指此控件被使用时,外部程序看到的属性名称,仅在外部引用时被使用。
Type:属性类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。
Variable name:变量名称。此属性在控件源文件中的变量名称,在编写控件源码时使用。
Notification function:提醒函数。当此属性被改变时,会触发此提醒函数。
Implementation:实现方式。指属性的三种类型:固有型,成员变量型,Get/Set方法型。固有型是指系统赋予的固有属性,如背景色,标题;成员变量型是用户自定义的属性;Get/Set方法型,可能是指只能通过Get/Set方法才能获取和改变的变量吧(这个没研究)。
2.2 添加控件方法
在“Automation”选项卡中,点击右边的“Add Method…”会弹出对话框:
External name:方法外部名称。
Internal name:方法内部名称。
Return type:返回值类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。
Implementation:实现方式。两种:固有方法,自定义方法。
Parameter list:参数列表。参数名称和参数类型:参数类型包含很多高级数据类型。
2.3 添加控件事件
切换到“ActiveX Events”选项卡中,点击右边的“Add Event…”会弹出对话框:
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产生了事件了。
同时可以通过“Control”-》“Invoke Method”来对控件的方法进行测试,测试的方法就是你输入参数,它返回计算结果(下面以自定义的方法funHello为例)。
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);
}