ActiveX编程

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.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值