VC++ IE控件(MFC ActiveX ocx)开发

1. 新建一个MFC ActiveX项目

在这里插入图片描述
在这里插入图片描述
"关于"对话框可用于参考实现自定义的控件函数

2. 新增三个辅助函数

2.1. 增加头文件"Cathelp.h"

#include "comcat.h"
#include "strsafe.h"

HRESULT CreateComponentCategory(CATID catid, WCHAR *catDescription);

HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

2.2. 增加源文件"Cathelp.cpp"

#include "stdafx.h"
#include "Cathelp.h"

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
	size_t len;
	// Make sure the provided description is not too long.
	// Only copy the first 127 characters if it is.
	// The second parameter of StringCchLength is the maximum
	// number of characters that may be read into catDescription.
	// There must be room for a NULL-terminator. The third parameter
	// contains the number of characters excluding the NULL-terminator.
	hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);
	if (SUCCEEDED(hr))
	{
		if (len > 127)
		{
			len = 127;
		}
	}
	else
	{
		//TODO: Write an error handler;
	}
	// The second parameter of StringCchCopy is 128 because you need 
	// room for a NULL-terminator.    
	hr = StringCchCopy(catinfo.szDescription, len + 1,
		catDescription);
	// Make sure the description is null terminated.
	catinfo.szDescription[len + 1] = '\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;
}

3. 修改"工程名.cpp"

本小节的所有代码都增加在"工程名.cpp"文件中

3.1. 增加头文件

#include "Cathelp.h"
#include "objsafe.h"

3.2. 定义CLSID_SafeItem

//在"工程名Ctrl.cpp"文件里找到
IMPLEMENT_OLECREATE_EX(CtestCtrl, "控件ProgID",0xa7e03b16,0x0ca1,0x4110,0x8b,0xa5,0xd9,0xce,0x30,0x78,0xe5,0xd5)

//将16进制部分拿来定义变量,这个就是控件的CLSID,注意有两个花括号{x{}}
const CATID CLSID_SafeItem = { 0xa7e03b16,0x0ca1,0x4110,{0x8b,0xa5,0xd9,0xce,0x30,0x78,0xe5,0xd5} };

3.3. 修改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);

    //下面这部分是增加的代码
	// Mark the control as safe for initializing.
	HRESULT  hr;
	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;

	// Mark the control as safe for scripting.

	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;
}

3.4. 修改DllUnregisterServer

STDAPI DllUnregisterServer(void)
{
	AFX_MANAGE_STATE(_afxModuleAddrThis);

	if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
		return ResultFromScode(SELFREG_E_TYPELIB);

	if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
		return ResultFromScode(SELFREG_E_CLASS);

	//下面这部分是增加的代码
	// Remove entries from the registry.
	HRESULT  hr;
	hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
	if (FAILED(hr))
		return hr;

	hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
	if (FAILED(hr))
		return hr;

	return NOERROR;
}

4. 实现IObjectSafety

4.1. 修改"工程名Ctrl.h"

//添加头文件
#include <objsafe.h>

//添加如下代码
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);

4.2. 修改"工程名Ctrl.cpp"

//添加如下代码
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);
}

5. 使用regsvr32注册ocx

//使用系统管理员权限注册
regsvr32  文件夹路径/文件名.ocx

6. 在HTML中引用

 <object id="MyOCX"
         classid="CLSID:a7e03b16-0ca1-4110-8ba5-d9ce3078e5d5" CODEBASE="文件夹路径/工程名.ocx" width="1024" height="768">
 </object>
 <script type="text/javascript">
 MyOCX.AboutBox();//此方法为自带方法,在"工程名.idl"中有定义,可以参考AboutBox()自定义需要的方法
 </script>

参考:

官方文档
Component Categories Manager
IObjectSafety

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值