ocx註冊成功但是頁面不顯示
解決方案有2種:
1、OCX註冊同時註冊安全入口
2、實現安全介面IObjectSafety
具體實現:
第一種:OCX註冊同時註冊安全入口
修改XXX.cpp檔案(OCXTest-XXX):
// OCXTest.cpp : COCXTestApp 和 DLL 註冊的實現。
#include "stdafx.h"
#include "OCXTest.h"
#include <objsafe.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
COCXTestApp NEAR theApp;
const GUID CDECL BASED_CODE _tlid =
{ 0xE62AE89, 0x4574, 0x470D, { 0x91, 0x25, 0x5D, 0xD3, 0xFB, 0xE6, 0x9D, 0x12 } };
const WORD _wVerMajor = 1;
const WORD _wVerMinor = 0;
// 與該控制元件的guid一致
const GUID CDECL CLSID_SafeItem =
{ 0x10b49e1a, 0x28d8, 0x44f2, { 0xb2, 0x53, 0xb, 0x31, 0x54, 0x79, 0x67, 0x54} };
// COCXTestApp::InitInstance - DLL 初始化
BOOL COCXTestApp::InitInstance()
{
BOOL bInit = COleControlModule::InitInstance();
return bInit;
}
// COCXTestApp::ExitInstance - DLL 終止
int COCXTestApp::ExitInstance()
{
// TODO: 在此新增您自己的模組終止程式碼。
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 - 將項新增到系統登錄檔
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 - 將項從系統登錄檔中移除
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
HRESULT hr = S_OK;
// 刪除控制元件初始化安全入口.
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;
}
第2種:實現安全介面IObjectSafety
需要標頭檔案:#include "objsafe.h"
1、在XXXCtrl.h檔案中DECLARE_DYNCREATE(CXXXCtrl)後新增:
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);
2、在XXXCtrl.cpp檔案中UpdateRegistry函式之後新增:
/////////////////////////////////////////////////////////////////////////////
// Interface map for IObjectSafety
BEGIN_INTERFACE_MAP( COCXTestCtrl, COleControl )
INTERFACE_PART(COCXTestCtrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()
/////////////////////////////////////////////////////////////////////////////
// IObjectSafety member functions
// Delegate AddRef, Release, QueryInterface
ULONG FAR EXPORT COCXTestCtrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(COCXTestCtrl, ObjSafe)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT COCXTestCtrl::XObjSafe::Release()
{
METHOD_PROLOGUE(COCXTestCtrl, ObjSafe)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT COCXTestCtrl::XObjSafe::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(COCXTestCtrl, 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
COCXTestCtrl::XObjSafe::GetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(COCXTestCtrl, 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
COCXTestCtrl::XObjSafe::SetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(COCXTestCtrl, 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);
}
3、IE如何響應ActiveX控制元件事件
第一種:手動實現連線點
這幾天在開發過程中遇到一個問題,即在網頁中無法響應ActiveX控制元件自定義事件。經查資料後,明白ActiveX控制元件的事件如果要
通過#等指令碼語言響應,必須實現IProvideClassInfo或者IProvideClassInfo2介面。因為指令碼語言必須通過這個介面獲
得控制元件的介面資訊。
用MFC ActiveX Control Wizard生成的專案,其介面的實現是通過巢狀類完成,要實現IProvideClassInfo介面我們可以按下列步驟進行:
1. 在COleControl的繼承類.h檔案中DECLARE_DYNCREATE(CXXXCtrl)後加入程式碼:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(ProvideClassInfo, IProvideClassInfo)
STDMETHOD_(HRESULT, GetClassInfo) (
/*[out] */ITypeInfo** ppTI
);
END_INTERFACE_PART(ProvideClassInfo);
2. 在COleControl的繼承類.cpp檔案中UpdateRegistry函式後加入程式碼,並實現介面:
BEGIN_INTERFACE_MAP( CMetaKM_FC_BCtrl, COleControl )
INTERFACE_PART(CMetaKM_FC_BCtrl, IID_IProvideClassInfo, ProvideClassInfo)
END_INTERFACE_MAP()
ULONG FAR EXPORT CMetaKM_FC_BCtrl::XProvideClassInfo::AddRef()
{
METHOD_PROLOGUE(CMetaKM_FC_BCtrl, ProvideClassInfo)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CMetaKM_FC_BCtrl::XProvideClassInfo::Release()
{
METHOD_PROLOGUE(CMetaKM_FC_BCtrl, ProvideClassInfo)
return pThis->ExternalRelease();
}
HRESULT STDMETHODCALLTYPE
CMetaKM_FC_BCtrl::XProvideClassInfo::QueryInterface (
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CMetaKM_FC_BCtrl, ProvideClassInfo)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
HRESULT STDMETHODCALLTYPE
CMetaKM_FC_BCtrl::XProvideClassInfo::GetClassInfo (
/* [out] */ITypeInfo** ppTypeInfo
)
{
METHOD_PROLOGUE(CMetaKM_FC_BCtrl, ProvideClassInfo)
HRESULT hr;
CLSID clsid;
pThis->GetClassID(&clsid);
hr = pThis->GetTypeInfoOfGuid(GetUserDefaultLCID(), clsid, ppTypeInfo);
return hr;
}
如果是用ATL COM Wizard生成的工程,那麼在New ATL Object時可以選擇Full Control,該選項預設已經實現IProvideClassInfo2介面
。如果選擇其他輕量級ActiveX物件,那麼實現IProvideClassInfo2介面也相當容易。因為ATL COM Wizard生成的工程,對於介面的實現
時通過多重繼承完成的,只有在介面定義中加入繼承IProvideClassInfo2即可。
1. 在介面定義中加入:
public IProvideClassInfo2Impl<&CLSID_MetaKM_FC_B, &DIID__IMetaKM_FC_BEvents, &LIBID_METAKM_FC_CTRLLib>
2.在BEGIN_COM_MAP(CMetaKM_FC_B)與END_COM_MAP()對中加入COM_INTERFACE_ENTRY(IProvideClassInfo)和COM_INTERFACE_ENTRY(IProvideClassInfo2)
第二種:通過ActiveX屬性通知IE
步驟:
在ActiveX中新增一個屬性:Idispatch* EventNotify;
對應變數為Idispatch* m_EventNotify;
屬性函式:
Idispatch* C***Ctrl::GetEventNotify(void)
{
return EventNotify;
}
void SetEventNotify(Idispatch* pVal)
{
m_EventNotify = pVal;
}
自定義函式作為事件通知函式:
void OnEventNotify()
{
if(m_EventNotify==NULL) return ;
DISPPARAMS dispparamNoArgs = {NULL,NULL,0,0};
HRESULT hr = m_EventNotify->Invoke(0, IID_NULL, LOCAL_USER_DEFAULT, DISPATCH_METHOD,
&dispparamNoArgs ,NULL,NULL,NULL);
}
現在ActiveX的事件做好了,只要在呼叫 OnEventNotify()就能激發。在Web中只要用#將事件函式名賦給控制元件的屬性EventNotify就能連通了。
例如:
<OBJECT id="obj" type="application/x-oleobject"
height="400" width="500" classid="CLSID:控制元件的guid" VIEWASTEXT>
</OBJECT>
<a id=process href="#:testevent()">test</a>
<script>
obj.EventNotify=eventfunc;
function eventfunc(){
// alert(111); }
function testevent(){
obj.DriveEvent();
}
</script>