1.VS2008下, 创建MFC ActiveX Control工程, 设置工程名为ESPackageOcx, 其他按照默认设置进行
2.对工程属性进行设置Debug&Release
01)输出目录为bin,中间目录为bin\$(ConfigurationName); Debug-共享dll; Release-静态dll;
02)Header Files更名为inc, Resource Files更名为res, Source Files更名为src;
03)resource.h, ESPackageOcx.rc, ESPackageOcx.rc2等资源文件移至res中; 其他文件自动分散到inc和src中;
04)禁止4996警告
3.在html页面中加入以下代码, 加载ocx控件, 其中classid在ESPackageOcx.idl中查找, 通常在文件末尾处
<object id="Object3" classid="clsid:37FDCD23-01C9-4655-A005-CC2C84B4458E" width="400" height="300">
</object>
在html页面中使用下面代码调用
var sum = Object1.TheFirstDispatchMethod(10, 21);
在html页面中使用下面代码接收事件
<script type="text/javascript" for="Object1" event="TheFirstEventMethod(a)">
alert("event="+a);
</script>
具体示例如下:
<html>
<head>
<title>ActiveX 测试</title>
<script type="text/javascript">
function FuncTest(aParam)
{
var sum = Object1.TheFirstDispatchMethod(10, 21);
alert("sum="+sum);
}
</script>
<script type="text/javascript" for="Object1" event="TheFirstEventMethod(a)">
alert("event="+a);
</script>
</head>
<body>
<div>
<button id="btnTest" οnclick="FuncTest(Clicked!)">
Click Test
</button>
</div>
<div>
<object id="Object1" classid="clsid:37FDCD23-01C9-4655-A005-CC2C84B4458E" width="400" height="300">
<!--
<param name="_Version" value="65536">
<param name="_ExtentX" value="13441">
<param name="_ExtentY" value="11615">
<param name="_StockProps" value="0">
-->
</object>
</div>
<div>
<object id="Object2" classid="clsid:37FDCD23-01C9-4655-A005-CC2C84B4458E" width="400" height="300">
<!--
<param name="_Version" value="65536">
<param name="_ExtentX" value="13441">
<param name="_ExtentY" value="11615">
<param name="_StockProps" value="0">
-->
</object>
</div>
</body>
</html>
4.在工程的类视图中, 展开工程ESPackageOcx, 展开ESPackageOcxLib, 在_DESPackageOcx上右击, 来添加调用接口(Dispatch interface), 会自动生成以下代码
01)在ESPackageOcxCtrl.h中生成枚举值
dispidTheFirstDispatchMethod = 1L;
02)在ESPackageOcxCtrl.h中生成成员函数
LONG TheFirstDispatchMethod(LONG a, LONG b);
03)在ESPackageOcx.idl中生成接口定义
[id(1), helpstring("method TheFirstDispatchMethod")] LONG TheFirstDispatchMethod(LONG a, LONG b);
04)在ESPackageOcxCtrl.cpp中生成映射关系
DISP_FUNCTION_ID(CESPackageOcxCtrl, "TheFirstDispatchMethod", dispidTheFirstDispatchMethod, TheFirstDispatchMethod, VT_I4, VTS_I4 VTS_I4)
05)在ESPackageOcxCtrl.cpp中生成函数实现
LONG CESPackageOcxCtrl::TheFirstDispatchMethod(LONG a, LONG b)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your dispatch handler code here
return a+b;
}
5.在工程的类视图中, 展开工程, 在CESPackageOcxCtrl上右击, 用来添加事件接口(Event dispatch interface), 会生成以下代码
01)在ESPackageOcxCtrl.h中生成枚举值
eventidTheFirstEventMethod = 2L;
02)在ESPackageOcxCtrl.h中生成内联成员函数
void TheFirstEventMethod(LONG a)
{
FireEvent(eventidTheFirstEventMethod, EVENT_PARAM(VTS_I4), a);
}
03)在ESPackageOcx.idl中生成接口定义
[id(2)] void TheFirstEventMethod(LONG a);
04)在ESPackageOcxCtrl.cpp中生成映射关系
EVENT_CUSTOM_ID("TheFirstEventMethod", eventidTheFirstEventMethod, TheFirstEventMethod, VTS_I4)
05)在工程中不要实现这个函数, 在工程某处去调用它, 函数的实现交给js代码
6.编译生成的ESPackageOcx.ocx需要在系统中注册, 才能使用:regsvr32 C:\My Path\ESPackageOcx.ocx;
编译工程时会自动注册它;
7.调试ocx:
01)在"工程--属性--配置--常规--调试"中, 命令(Command)中填入IE浏览器路径, 参数(Command Arguments)中填入启动的网页
02)创建窗口应用程序, 在窗口中加入ESPackageOcx.ocx控件
8.浏览器的安全警告:
01) 在加载ocx控件时, 会提示"...浏览器已限制此网页运行可以访问计算机的脚本或ActiveX控件...",
点击提示后会弹框"允许活动内容(如脚本和ActiveX控件)可能对您有所帮助. 但是活动内容可能也会危害您的计算机."
02) 在初次调用ocx控件接口时, 会提示"在此页上的ActiveX控件和本页的其他部分的交互可能不安全."
9.据说是消除安全警告02的代码, 在ESPackageOcx.cpp中加入以下代码
#include "Objsafe.h"
const GUID CDECL CLSID_SafeItem = {0x89db509f, 0x8681, 0x4f1f, {0x90, 0xb, 0xb5, 0x37, 0x45, 0x76, 0x79, 0x91}};
// 创建组件种类
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if(FAILED(hr))
return hr;
// Make sure the HKCR\Component Categories\{..catid...}
// key is registered.
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
// Make sure the provided description is not too long.
// Only copy the first 127 characters if it is.
int len = wcslen(catDescription);
if(len>127)
len = 127;
wcsncpy(catinfo.szDescription, catDescription, len);
// Make sure the description is null terminated.
catinfo.szDescription[len] = '\0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
// 注册组件种类
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if(SUCCEEDED(hr))
{
// Register this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if(pcr != NULL)
pcr->Release();
return hr;
}
// 卸载组件种类
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if(SUCCEEDED(hr))
{
// Unregister this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
}
if(pcr != NULL)
pcr->Release();
return hr;
}
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if(!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if(!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
HRESULT hr = S_OK ;
// 标记控件初始化安全.
// 创建初始化安全组件种类
hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
if(FAILED(hr))
return hr;
// 注册初始化安全
hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
if(FAILED(hr))
return hr;
// 标记控件脚本安全
// 创建脚本安全组件种类
hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
if(FAILED(hr))
return hr;
// 注册脚本安全组件种类
hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
if(FAILED(hr))
return hr;
return NOERROR;
}
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
HRESULT hr;
// 删除控件初始化安全入口.
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
if(FAILED(hr))
return hr;
// 删除控件脚本安全入口
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
if(FAILED(hr))
return hr;
if(!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
return ResultFromScode(SELFREG_E_TYPELIB);
if(!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
10.IE8或者IE9下调试时无法进入断点.
原因: IE8/IE9默认是多进程工作的, 所以默认情况下不能进行调试
解决: 关闭IE的保护模式, 避免IE用多进程方式打开网页, 否则调试器启动的IE进程跟网页所在的IE进程不同, 就不能中断. 通过修改注册表改为多进程工作的时候, 启动的IE进程和加载要调试的ocx的IE进程不是一个进程, 所以不能调试
1. 点击【开始】->【运行】 命令:regedit.
2. 定位到HKEY_LOCALMACHINE -> SOFTWARE -> Microsoft -> Internet Explorer -> Main
3. 在【右边区域】【右键】新建一个名称为TabProcGrowth的DWORD值, 数值数据设置为0.