MFC OCX控件实现安全初始化和脚本安全的方法

来源:互联网 发布:守望先锋 英雄详细数据 编辑:程序博客网 时间:2024/05/23 02:01

如果不实现该IObjectSafety接口,IE调用时会有如下提示信息:



解决方法有两种,如下:

方法1:通过IObjectSafety接口实现

具体步骤:

(1)在TestOCXCtrl.h中
#include <objsafe.h> // for IObjectSafety; in ActiveX SDK
  (2)在TestOCXCtrl.h中
   
        DECLARE_OLECREATE_EX(CTestOCXCtrl)    // Class factory and guid

//***************************************************************add begin
//ISafeObject
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);

//ISafeObject
//***************************************************************add end
DECLARE_OLETYPELIB(CTestOCXCtrl)      // GetTypeInfo
DECLARE_PROPPAGEIDS(CTestOCXCtrl)     // Property page IDs
DECLARE_OLECTLTYPE(CTestOCXCtrl)// Type name and misc status

   (3)在TestOCXCtrl.cpp中
// Message map

BEGIN_MESSAGE_MAP(CTestOCXCtrl, COleControl)
//{{AFX_MSG_MAP(CTestOCXCtrl)
// NOTE - ClassWizard will add and remove message map entries
//    DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


//***************************************************************add begin
BEGIN_INTERFACE_MAP( CTestOCXCtrl, COleControl )
INTERFACE_PART(CTestOCXCtrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()
//***************************************************************add end

/////////////////////////////////////////////////////////////////////////////
// Dispatch map
................................
增加IObjectSafety接口实现方法

////***************************************************************add begin

// IObjectSafety member functions

// Delegate AddRef, Release, QueryInterface

ULONG FAR EXPORT CTestOCXCtrl::XObjSafe::AddRef()

{

    METHOD_PROLOGUE(CTestOCXCtrl, ObjSafe)

return pThis->ExternalAddRef();

}

ULONG FAR EXPORT CTestOCXCtrl::XObjSafe::Release()

{

    METHOD_PROLOGUE(CTestOCXCtrl, ObjSafe)

return pThis->ExternalRelease();

}

HRESULT FAR EXPORT CTestOCXCtrl::XObjSafe::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)

{

    METHOD_PROLOGUE(CTestOCXCtrl, 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 

CTestOCXCtrl::XObjSafe::GetInterfaceSafetyOptions( 

 /* [in] */ REFIID riid,

 /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,

 /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)

{

METHOD_PROLOGUE(CTestOCXCtrl, 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 

CTestOCXCtrl::XObjSafe::SetInterfaceSafetyOptions( 

 /* [in] */ REFIID riid,

 /* [in] */ DWORD dwOptionSetMask,

 /* [in] */ DWORD dwEnabledOptions)

{

    METHOD_PROLOGUE(CTestOCXCtrl, 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);

}

//***************************************************************add end


方法2:通过修改注册表实现,方法如下:

// Define the GUID associated with the safety component categories:
const CATID CATID_SafeForScripting = {0x7dd95801,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4}};
const CATID CATID_SafeForInitializing  = {0x7dd95802,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4}};


// Helper function to create a component category and associated description
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);
// Helper function to register a CLSID as belonging to a component category
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

// 卸载组件种类 
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

// Helper function to create a component category and associated description
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 = {0};
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;
}

// Helper function to register a CLSID as belonging to a component category
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;    

    Define the GUID associated with your control. 
For simplicity, you can borrow the GUID from the IMPLEMENT_OLECREATE_EX macro in the xxxCtrl.cpp file for the control. 
Adjust the format slightly so that it looks like the following:
    const CATID CLSID_SafeItem =
 { 0x43bd9e45, 0x328f, 0x11d0,
 { 0xa6, 0xb9, 0x0, 0xaa, 0x0, 0xa7, 0xf, 0xc2 } };
注意:此处为控件的GUID . 

To mark your control as both Safe for Scripting and Initialization, modify the DllRegisterServer function as follows:
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);

if (FAILED( CreateComponentCategory(
CATID_SafeForScripting,
L"Controls that are safely scriptable") ))
return ResultFromScode(SELFREG_E_CLASS);

if (FAILED( CreateComponentCategory(
CATID_SafeForInitializing,
L"Controls safely initializable from persistent data") ))
return ResultFromScode(SELFREG_E_CLASS);

if (FAILED( RegisterCLSIDInCategory(
CLSID_SafeItem, CATID_SafeForScripting) ))
return ResultFromScode(SELFREG_E_CLASS);

if (FAILED( RegisterCLSIDInCategory(
CLSID_SafeItem, CATID_SafeForInitializing) ))
return ResultFromScode(SELFREG_E_CLASS);

return NOERROR;
}

2 反注册时
You would not normally modify the DllUnregisterServer function for these two reasons:
(1)You would not want to remove a component category because other controls may be using it.
(2)Although there is an UnRegisterCLSIDInCategory function defined, 
  by default DllUnregisterServer removes the control's entry from the registry entirely. 
  Therefore, removing the category from the control's registration is of little use.


原创粉丝点击