開發完ActiveX控件後,對於發佈也有許多麻煩,稍微不小心你的ActiveX便變成一個紅叉,以下所介紹的每一點都不可或缺,經過這幾點後ActiveX控件將順利的顯示在Internet 網頁中,這時候可以看到win7中C:\Windows\Downloaded Program Files目錄中有你所發佈的Activex文件,並可在瀏覽器的加載項中找到已加載的ActiveX控件:
1.ActiveX的發佈首先當然需要一個ActiveX控件,通過MFC ActiveX基礎1:http://blog.csdn.net/acsder2010413/article/details/26385535生成DemoActiveX.ocx
2.將ActiveX控件放在網頁中,以下代碼爲html使用ActiveX示例
<html>
<body>
<object classid="clsid:826CAAE8-CEAC-4317-BAC7-60BF39279C4F" codebase="UpgradeController.ocx#version=1,0,0,1" width="600" height="500"></object>
</body>
</html>
html使用Object標籤來支持各種插件,對於html object支持的插件情況可見:http://www.w3school.com.cn/html/html_object.asp
Object標籤可以支持向Html中插入Activex控件,這裏用到兩個主要屬性:
a. classid
classid | class ID | 定義嵌入 Windows Registry 中或某個 URL 中的類的 ID 值,此屬性可用來指定瀏覽器中包含的對象的位置,通常是一個 Java 類。 |
codebase | URL | 定義在何處可找到對象所需的代碼,提供一個基準 URL。 |
對於Object標籤詳見:http://www.w3school.com.cn/tags/tag_object.asp
3. 爲ActiveX控件添加IObjectSafty接口,使得ActiveX被註冊爲安全控件,並且順利的通過Internet Explorer的安全檢查(經驗證可通過默認安全級別(中-高級別))
未添加IObjectSafty接口的ActiveX控件,將不能通過Internet Explorer的默認安全級別(Internet選項-》安全),需要通過降低安全級別並啓用有關ActiveX控件的安全選項,這裏稍微設置不好就可能使ActiveX控件無法使用,故顯然添加IObjectSafty接口順利通過安全級別纔是最佳選擇。
對於IObjectSafty接口與ActiveX控件可見:http://blog.csdn.net/optman/article/details/1698070
那麼如何實現IObjectSafty接口
以下IObjectSafty接口實現經驗證可行,引自:http://jiangsy1107.blog.sohu.com/201048568.html
默認情況下,編譯的MFC Activex控件,只能在本地代碼中運行,要想放在服務器通過IE遠程訪問,需要設置其初始化和腳本運行的安全性,做以下修改:
在“工程名.cpp”文件中,增加以下方法:
// 創建組件種類
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_s(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和DllUnregisterServer這個兩個方法做如下修改:
// 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);
// 標記控件初始化安全.
// 創建初始化安全組件種類
hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
if (FAILED(hr)) return hr;
// 註冊初始化安全
hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForInitializing);
if (FAILED(hr)) return hr;
// 標記控件腳本安全
// 創建腳本安全組件種類
hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
if (FAILED(hr)) return hr;
// 註冊腳本安全組件種類
hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);
if (FAILED(hr)) return hr;
return NOERROR;
}
// DllUnregisterServer - 將項從系統註冊表中移除
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(BASED_CODE _tlid , CATID_SafeForInitializing);
if (FAILED(hr)) return hr;
// 刪除控件腳本安全入口
hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);
if (FAILED(hr)) return hr;
return NOERROR;
}
其中CATID_SafeForInitializing和CATID_SafeForScripting兩個是guid,可以通過VC自帶的guid生成工具自動生成。
下一步,實現IobjectSafety接口,步驟:
打開 “工程名Ctrl.h”
加入#include<objsafe.h>,
搜索
DECLARE_DYNCREATE(C工程名Ctrl)
在其下面添加:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)
STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (
REFIID riid,
DWORD __RPC_FAR *pdwSupportedOptions,
DWORD __RPC_FAR *pdwEnabledOptions
);
STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (
REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions
);
END_INTERFACE_PART(ObjSafe);
打開“工程名Ctl.cpp”
在
BOOL C工程名Ctrl::C工程名CtrlFactory::UpdateRegistry(BOOL bRegister)
方法上面添加以下代碼:
/////////////////////////////////////////////////////////////////////////////
// Interface map for IObjectSafety
BEGIN_INTERFACE_MAP(C工程名Ctrl, COleControl)
INTERFACE_PART(C工程名Ctrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()
/////////////////////////////////////////////////////////////////////////////
// IObjectSafety member functions
// Delegate AddRef, Release, QueryInterface
ULONG FAR EXPORT C工程名Ctrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(C工程名Ctrl, ObjSafe)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT C工程名Ctrl::XObjSafe::Release()
{
METHOD_PROLOGUE(C工程名Ctrl, ObjSafe)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT C工程名Ctrl::XObjSafe::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(C工程名Ctrl, 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
C工程名Ctrl::XObjSafe::GetInterfaceSafetyOptions(
REFIID riid,
DWORD __RPC_FAR *pdwSupportedOptions,
DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(C工程名Ctrl, 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
C工程名Ctrl::XObjSafe::SetInterfaceSafetyOptions(
REFIID riid,
DWORD dwOptionSetMask,
DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(C工程名Ctrl, 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);
}
到此,ActiveX插件就可以註冊爲安全控件了。
另:網上有介紹將ActiveX打包成cab並添加簽名來發布,可通過Internet Explorer的安全檢驗,但經過試驗沒有成功。