文章目录
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>