随笔-9  评论-21  文章-63  trackbacks-0

首先要说明的是 web上用activex是门被抛弃的技术。为什么这么说,主要基于以下几个原因:1.功能过于强大,强大到一旦安装,他所具有的权限可以做任何事,极易被人利用做坏事(相信大家都有浏览网页后莫名被安装流氓软件的经历,当然流氓软件利用的方式不止控件一种);2。通过网页下载控件的中间过程受到操作系统、杀毒软件、浏览器等多方面因素限制,这使你的控件产品未必能在所有用户的电脑上正常使用;3。最恶心的一点,未签名没有正规安全证书的控件,在最新的浏览器上(IE7等)默认安全策略是直接屏蔽掉的,而你如果想要获取这个信任,需要向微软等少数单位申请,花费有多少?据说是每年4千多。。。
   看了以上如果你还是想要知道步骤,如下:
一。用Vc++6.0新建工程里的向导创建MFC activeX controlWizard,细节不说了,根据你控件需要了,略有不同,问题不会太大。

二。你控件代码的主xx.cpp(非xxCtr.cpp)文件中添加安全接口函数,否则每次运行控件时IE都会给出安全提示,很烦!
#include "comcat.h"
#include "Objsafe.h"

// 本控件的CLSID,注册表用
const GUID CDECL CLSID_SafeItem ={ 0x7AE7497B, 0xCAD8, 0x4E66,
                      { 0xA5,0x8B,0xDD,0xE9,0xBC,0xAF,0x6B,0x61 } };
// 版本控制
const WORD _wVerMajor = 1;
// 次版本号
const WORD _wVerMinor = 0;


/////////////////////////////////////////////////////////////////////
// CICCardApp::InitInstance - DLL initialization

BOOL CICCardApp::InitInstance()
{
    BOOL bInit = COleControlModule::InitInstance();

    if (bInit)
    {
   
    }

    return bInit;
}


//////////////////////////////////////////////////////////////////////
// CICCardApp::ExitInstance - DLL termination

int CICCardApp::ExitInstance()
{
    return COleControlModule::ExitInstance();
}


//////////////////////////////////////////////////////////////////////

// 创建组件种类
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)
{
    HRESULT hr;

    AFX_MANAGE_STATE(_afxModuleAddrThis);

    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
        return ResultFromScode(SELFREG_E_TYPELIB);

    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
        return ResultFromScode(SELFREG_E_CLASS);

    // 标记控件初始化安全.
    // 创建初始化安全组件种类
    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)
{
    HRESULT hr;

    AFX_MANAGE_STATE(_afxModuleAddrThis);

    if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
        return ResultFromScode(SELFREG_E_TYPELIB);

    if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
        return ResultFromScode(SELFREG_E_CLASS);

    // 删除控件初始化安全入口.
    hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
    if (FAILED(hr))
        return hr;
    // 删除控件脚本安全入口
    hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
    if (FAILED(hr))
        return hr;

//////////////////////////
    return NOERROR;
}

三。添加自己的代码到控件文件xxCtr.cpp中,这里最好通过向导添加View->ClassWard->automation。

四。编译生成你的xx.ocx控件文件,这个文件其实就是个DLL函数库,只是后缀不同而已。

五。制作xx.inf文件用于之后的空间打包压缩。红色部分为需要根据你自己情况修改的地方。
[version]  
signature="$CHICAGO$"  
AdvancedINF=1.0  
[Add.Code]  
xx.ocx=xx.ocx  
[xx.ocx]
  
file-win32-x86=thiscab  
clsid={351FC603-D784-4B8D-BA2C-33C212EC5BAA}  
FileVersion=1,0,0,1  
RegisterServer=yes
  

六。打包压缩成xx.cab文件。你需要用到给控件签名的一些工具:cabarc.exe、signcode.exe,另外你可能需要用于制作自己试验证书的工具:makecert.exe、cert2spc.exe。
制作根证书MyCert.cer和私钥myKey.PVK:
makecert -r  -sv "myKey.PVK"  -n CN="xx Electric Industry Co. Ltd."   MyCert.cer
CERT2SPC MyOKIcert.cer MyOKIcert.spc
打包压缩空间为xx.cab:
cabarc -s 6144 n xx.cab xx.ocx xx.inf
数字签名cab文件
双击signocode.exe文件,图形化签名,注意要通过自定义选择自己的证书和私钥而不是选择系统已有的。

七。在你要用空间的Web上添加代码:
             <td colspan="2"><object id='t1' codeBase=/UserMode/xx.cab#version=1,0,0,1 classid='clsid:F3530445-A287-4A0B-AC3E-C4AF2B63EBA7' height=0 width=0 ></object></td>

八。调用控件内方法。通过javascript直接调用控件对象的方法就行了,比如调用空间中存在的一个download()方法: document.getElementByID("t1").download();

八。客户端使用,其他人从网上下载到你的控件后,如果是Window XP系统的话,需要先导入证书为可信任(详细到Google上搜索导入证书,很容易),再安装控件,之后才能用;而如果是Window2000用户则只要安装控件就可以使用了。

九。控件的删除。Internet选项-〉设定-〉显示对象,直接看到你的xx.cab文件,Del掉就行了,注册表中信息会自动消除掉,当然你也可以直接到注册表中删除对应xx.inf中列出的键值的项。

十。升级。只要在源代码中更改xx.rc文件中对应的那些1.0.0.1为你的新版本号,并同时更改你调用控件的web上的版本号就可以了,下一次客户访问这个页面时会自动提示安装新控件,新控件会覆盖就版本的控件。

   以上仅供参考,本人也是新手,最近工作需要用控件才能完成一些功能,以上包含了我开发过程中碰到的诸多问题,希望对所有人能有所帮助

posted on 2007-03-29 09:35 Flutist 阅读(7100) 评论(3)  编辑 收藏 引用 所属分类: 资料查询库

评论:
# re: web上用Activex控件开发步骤(MFC) 2007-08-03 17:21 | 上的上的
最近也需要看这方面的内容,比较郁闷.现在搞了以后估计也不用了.  回复  更多评论
  
# re: web上用Activex控件开发步骤(MFC) 2008-09-10 09:11 | from yantai
楼主啊,为什么我的控件CAB下载后,本机可以运行。但其他机器就下载不全,可以说没法调用后台程序。我很郁闷。

email:ren_xs@163.com
=======
我的 setup.inf

; Sample INF file for POLYGON.DLL
[version]
; version signature (same for both NT and Win95) do not remove
signature="$CHICAGO$"
AdvancedINF=2.0

[Add.Code]
AtlActiveX.dll=AtlActiveX.dll
TestDll.dll=TestDll.dll
IbmsSerialPort.dll=IbmsSerialPort.dll
setup.inf=setup.inf

[install.files]
AtlActiveX.dll=AtlActiveX.dll
TestDll.dll=TestDll.dll
IbmsSerialPort.dll=IbmsSerialPort.dll
setup.inf=setup.inf


[AtlActiveX.dll]
clsid={4AE870B5-C7FB-4171-A47E-7F57AFD86F67}
file-win32-x86=thiscab
FileVersion=1,0,0,1
DestDir=11
RegisterServer=yes

[TestDll.dll]
file-win32-x86=thiscab
DestDir=11
FileVersion=1,0,0,1
RegisterServer=yes

[IbmsSerialPort.dll]
file-win32-x86=thiscab
DestDir=11
FileVersion=1,0,0,1
RegisterServer=yes

[setup.inf]
file=thiscab

[RegisterFiles]
%11%\AtlActiveX.dll


; end of INF file

我的安装信息  回复  更多评论
  
# re: web上用Activex控件开发步骤(MFC) 2010-03-04 00:42 | dwordcn@mail.com
大哥,在vc自带的测试的activex的容器中是可以的,但是在页面中就不行了,页面错误:对象不支持此属性和方法;如果可以吧完整的工程发到我邮箱里谢谢了!能带上你那个打包工具更好  回复  更多评论
  
只有注册用户登录后才能发表评论。