【转】COM组件开发实践(三)

本文详细介绍如何在MFC和ATL中创建安全的ActiveX控件,包括标记控件为安全及数字签名的方法,并提供了具体步骤和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:http://www.cnblogs.com/phinecos/archive/2008/08/07/1263270.html

 

前面两篇文章分别介绍了MFC ActiveX应用程序和使用ATL开发ActiveX的简单实例,但还有两个问题需要解决:

1)标记ActiveX控件为安全的控件 2)对控件进行数字签名。本文将结合这两点进行简单的介绍。

Building a Safe ActiveX Control

      如何不想办法将控件标记为安全的,就会在Web页面与控件进行交互时出现如下图的警告信息:

     下面将分别介绍在MFC ActiveX和ATL中如何标记一个控件为安全的控件。

     要标记一个MFC ActiveX控件为安全,可以仿照下面代码修改而得:

 

//  CardScan.cpp : CCardScanApp 和DLL 注册的实现。
#include  " stdafx.h "
#include  " CardScan.h "
#include  " comcat.h "
#include  " strsafe.h "
#include  " objsafe.h "

CCardScanApp theApp;
const  GUID CDECL BASED_CODE _tlid  =
        {  0x29959268 ,  0x9729 ,  0x458E , {  0xA8 ,  0x39 ,  0xBB ,  0x39 ,  0x2E ,  0xCB ,  0x7E ,  0x37  } };
const  WORD _wVerMajor  =   1 ;
const  WORD _wVerMinor  =   0 ;
const  CATID CLSID_SafeItem  =
{ 0xB548F3C7 , 0x2135 , 0x4242 ,{ 0x92 , 0x0B , 0xA7 , 0xBD , 0xEE , 0x6D , 0x2B , 0xA3 }};

// { 0x36299202, 0x9ef, 0x4abf,{ 0xad, 0xb9, 0x47, 0xc5, 0x99, 0xdb, 0xe7, 0x78}};
//  CCardScanApp::InitInstance - DLL 初始化
BOOL CCardScanApp::InitInstance()
{
    BOOL bInit  =  COleControlModule::InitInstance();
     if  (bInit)
    {
    }
     return  bInit;
}
//  CCardScanApp::ExitInstance - DLL 终止
int  CCardScanApp::ExitInstance()
{
     return  COleControlModule::ExitInstance();
}
HRESULT CreateComponentCategory(CATID catid, CHAR  * 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
    size_t len;
     //  Make sure the provided description is not too long.
     //  Only copy the first 127 characters if it is.
     //  The second parameter of StringCchLength is the maximum
     //  number of characters that may be read into catDescription.
     //  There must be room for a NULL-terminator. The third parameter
     //  contains the number of characters excluding the NULL-terminator.
    hr  =  StringCchLength(catDescription, STRSAFE_MAX_CCH,  & len);
     if  (SUCCEEDED(hr))
    {
         if  (len > 127 )
        {
            len  =   127 ;
        }
    }   
     else
    {
         //  TODO: Write an error handler;
    }
     //  The second parameter of StringCchCopy is 128 because you need 
     //  room for a NULL-terminator.
    hr  =  StringCchCopy(COLE2T(catinfo.szDescription), len  +   1 , catDescription);
     //  Make sure the description is null terminated.
    catinfo.szDescription[len  +   1 ]  =   ' /0 ' ;
    hr  =  pcr -> RegisterCategories( 1 ,  & catinfo);
    pcr -> Release();
     return  hr;
}
//  HRESULT RegisterCLSIDInCategory -
//       Register your component categories information
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 - Remove entries from the registry
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 - 将项添加到系统注册表

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);
     //  Mark the control as safe for initializing.
    hr  =  CreateComponentCategory(CATID_SafeForInitializing, 
        _T( " Controls safely initializable from persistent data! " ));
     if  (FAILED(hr))
         return  hr;
    hr  =  RegisterCLSIDInCategory(CLSID_SafeItem, 
        CATID_SafeForInitializing);
     if  (FAILED(hr))
         return  hr;
     //  Mark the control as safe for scripting.
    hr  =  CreateComponentCategory(CATID_SafeForScripting, 
        _T( " Controls safely  scriptable! " ));
     if  (FAILED(hr))
         return  hr;
    hr  =  RegisterCLSIDInCategory(CLSID_SafeItem, 
        CATID_SafeForScripting);
     if  (FAILED(hr))
         return  hr;
     return  NOERROR;
}

//  DllUnregisterServer - 将项从系统注册表中移除

STDAPI DllUnregisterServer( void )
{
    HRESULT hr;
    AFX_MANAGE_STATE(_afxModuleAddrThis);
     //  Remove entries from the registry.
    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;
}

     这里值得注意的一个地方是DllUnregisterServer函数,在这段代码中,我是将

hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);

hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);

这两句代码放在

if  ( ! AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))

            return  ResultFromScode(SELFREG_E_TYPELIB);

       if  ( ! COleObjectFactoryEx::UpdateRegistryAll(FALSE))

            return  ResultFromScode(SELFREG_E_CLASS);

这两句代码的前面,如果你查阅MSDN,将会发现它上面的顺序和我是相反的,这应该是微软的一个错误代码,如果按照MSDN的代码来写,则你使用regsvr32 -u CardScan.ocx反注册时会报下面的错误:

调整为我所说的顺序就没问题了。

2)要标记使用ATL写的ActiveX控件为安全的控件,这比MFC要简单的多,只需要在控件头文件中增加几行代码就可以了:

class  ATL_NO_VTABLE CTestCtrl :
    …
     public  IObjectSafetyImpl < CTestCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER |  INTERFACESAFE_FOR_UNTRUSTED_DATA > ,

然后在COM映射表中增加一项:

BEGIN_COM_MAP(CTestCtrl)
    …
    COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()

Building a Signed ActiveX Control

      ActiveX控件是个危险的东西,如果不对其合法性进行数字签名和验证,IE是会拒绝其安装的。

      工具包准备:CABARC.exe, cert2spc.exe, makecab.exe, makecert.exe, signcode.exe(或新版本中的signtool),以上小工具都可以在VS的安装路径下"Common7"Tools"Bin找到,或去微软官方网站上下载。

ActiveX控件的安装过程中,一部分工作就是自注册,这需要控件在VERSIONINFO结构中定义OLESelfRegister值,你可以对资源文件进行编辑如下

BEGIN
    BLOCK  " StringFileInfo "
    BEGIN
        BLOCK  " 080403a8 "
        BEGIN
            VALUE  " CompanyName " ,   " TODO: <公司名> "
            VALUE  " FileDescription " ,   " TODO: <文件说明> "
            VALUE  " FileVersion " ,   " 1.0.0.1 "
            VALUE  " InternalName " ,   " CardScan.ocx "
            VALUE  " LegalCopyright " ,   " TODO: (C) <公司名>。保留所有权利。 "
            VALUE  " OLESelfRegister " ,   " /0 "
            VALUE  " OriginalFilename " ,   " CardScan.ocx "
            VALUE  " ProductName " ,   " TODO: <产品名> "
            VALUE  " ProductVersion " ,   " 1.0.0.1 "
         END
     END
    BLOCK  " VarFileInfo "
    BEGIN
        VALUE  " Translation " ,   0x804 ,   936
     END
END

打包为CAB文件

因为ActiveX控件要放在网站上供客户下载到本地,因此压缩是必需的。一段典型的html代码如下:

< OBJECT  ID ="FuckATL1"   
CODEBASE  ="http://localhost:8080/CardScan.cab"
CLASSID ="CLSID:B548F3C7-2135-4242-920B-A7BDEE6D2BA3"  WIDTH =300  HEIGHT =200
/>

CODEBASE就指明了要下载的压缩包,其中包含了oxc,dll控件等所需要的文件。

通常CAB文件包含了一个INF文件,它用来描述CAB文件的所有细节信息,下面举个简单例子,代码如下:

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

[Add . Code]
CardScan . ocx = CardScan . ocx
CardScan . inf = CardScan . inf

[CardScan . ocx]
file-win32-x86 = thiscab
clsid = {B548F3C7- 2135 - 4242 -920B-A7BDEE6D2BA3} 
FileVersion = 1 , 0 , 0 , 1  
RegisterServer = yes

[CardScan . inf]
file = thiscab
;   end  of INF file

至于打包就不赘述了,详尽的图解过程请看《如何给ActiveX数字签名(Step by Step, Delphi)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值