1. 程式人生 > >ocx註冊成功但是頁面不顯示

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>