MFC ActiveX开发基础2:ActiveX控件在Internet上发布

来源:互联网 发布:最全私人网络理财投资 编辑:程序博客网 时间:2024/06/05 09:16

开发完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

classidclass ID定义嵌入 Windows Registry 中或某个 URL 中的类的 ID 值,此属性可用来指定浏览器中包含的对象的位置,通常是一个 Java 类。b.codebase

codebaseURL定义在何处可找到对象所需的代码,提供一个基准 URL。上述html例子中将网页与ActiveX控件放到同一目录下,所以codebase属性可以不设路径。大家应该发现这个codebase设置的属性中文件路径名后还带有“#version1.0.0.1”,version实际是用来指定要发布的Activex的版本号,该版本号需要与ocx文件的版本号(文件属性->详细信息中查看)对应上,用来告诉浏览器是否要更新本地的ActiveX控件,当#version中指定的版本号大于本地文件版本时浏览器便会提示用户进行Activex的更新,新的ocx文件将被更新到C:\Windows\Downloaded Program Files\CONFLICT.n系列文件夹中

对于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的安全检验,但经过试验没有成功。

0 0