Posted on 2011-01-13 20:44 一桶浆糊

这是上一篇博客《宏定义的极致发挥---让你的普通C++类轻松支持IDispatch自动化接口》所展示的示例代码的改进版,改进之处有:

  • 1、如果不想直接提供成员作为属性,可以用成员函数的方式提供属性读写。 
    2、支持基类映射表,即如果基类也实现了映射表,派生类不用重复填表,自动合并基类表项。唯一的要求就是DISPID不要重复。 
    3、可以同时合并多个基类映射表。 
    4、添加可选参数支持,比如某个方法有5个参数,后3个为可选参数(有默认值),那么调用者可以只用2个参数来调用。 
    5、添加DISPID_VALUE支持,类似于VB中的对象默认属性。

简单的使用示例:

class CAnimal
{
public:
bool Sex; Begin_Disp_Map(CAnimal)
Disp_Property(1, Sex, bool)
End_Disp_Map()
}; class CDog : public CAnimal
{
public:
CString Name;
long Height; void Drink();
bool Eat(long lType, long lNum); HRESULT GetName(VARIANT* pvName);
HRESULT SetName(VARIANT* pvName); Begin_Disp_Map(CDog, CAnimal)
Disp_Property(2, Name)
Disp_PropertyGet(3, Height, long)
Disp_Method(4, Drink, void, 0)
Disp_Method(5, Eat, bool, 2, long, long)
End_Disp_Map()
};

  

从示例代码看出跟原始版本有如下不同:

1. 基类CAnimal也有映射表,意思是基类可以独立变成自动化对象。 
2. CDog可以继承CAnimal的映射表,只需要把基类名加在起始表项里,Begin_Disp_Map(CDog, CAnimal)。如果不想继承基类映射表,去掉基类类名即可,例如 Begin_Disp_Map(CDog)。如果CDog同时派生自另一个也有映射表的基类,比如CFourLegs,可以这样写 Begin_Disp_Map(CDog, CAnimal, CFourLegs)。这样做的话,CDog 将自动拥有 Sex 属性。 
3. Name属性将不再直接处理 Name 成员变量,而是通过GetName/SetName来读取和设置,具体的类型转换将由两个函数完成。

以上并没有列举具有可选参数的方法的填表用法,稍微有点复杂,有时间的话在下一篇介绍。

好了,下面是完整的头文件:

#ifndef __MACRO_H__
#define __MACRO_H__ #pragma once #ifndef __cplusplus
#error macro.h requires C++ compilation (use a .cpp suffix)
#endif #if (_MSC_VER < 1400)
#error macro.h requires Visual C++ 2005 and above.
#endif #pragma warning(push)
#pragma warning(disable:4800) #ifndef DISPID_EXPANDO_BASE
#define DISPID_EXPANDO_BASE 3000000
#define DISPID_EXPANDO_MAX 3999999
#define IsExpandoDispid(dispid) (DISPID_EXPANDO_BASE <= dispid && dispid <= DISPID_EXPANDO_MAX)
#endif // DISPID_EXPANDO_BASE //////////////////////////////////////////////////////////////////////////
// 基础工具宏定义 #define __for_each_number(v, ...) /
v(0, __VA_ARGS__) /
v(1, __VA_ARGS__) /
v(2, __VA_ARGS__) /
v(3, __VA_ARGS__) /
v(4, __VA_ARGS__) /
v(5, __VA_ARGS__) /
v(6, __VA_ARGS__) /
v(7, __VA_ARGS__) /
v(8, __VA_ARGS__) /
v(9, __VA_ARGS__) /
v(10, __VA_ARGS__) /
v(11, __VA_ARGS__) /
v(12, __VA_ARGS__) /
v(13, __VA_ARGS__) /
v(14, __VA_ARGS__) /
v(15, __VA_ARGS__) #define __for_each_number_base1(v, ...) /
v(1, __VA_ARGS__) /
v(2, __VA_ARGS__) /
v(3, __VA_ARGS__) /
v(4, __VA_ARGS__) /
v(5, __VA_ARGS__) /
v(6, __VA_ARGS__) /
v(7, __VA_ARGS__) /
v(8, __VA_ARGS__) /
v(9, __VA_ARGS__) /
v(10, __VA_ARGS__) /
v(11, __VA_ARGS__) /
v(12, __VA_ARGS__) /
v(13, __VA_ARGS__) /
v(14, __VA_ARGS__) /
v(15, __VA_ARGS__) // 数值减的常数
#define __cntdec_0 0
#define __cntdec_1 0
#define __cntdec_2 1
#define __cntdec_3 2
#define __cntdec_4 3
#define __cntdec_5 4
#define __cntdec_6 5
#define __cntdec_7 6
#define __cntdec_8 7
#define __cntdec_9 8
#define __cntdec_10 9
#define __cntdec_11 10
#define __cntdec_12 11
#define __cntdec_13 12
#define __cntdec_14 13
#define __cntdec_15 14 #define __cntdec(n) __cntdec_##n // 连接两个符号
#define __connect2(x, y) x##y
#define __connect(x, y) __connect2(x, y) // 把符号变成字符串
#define __to_string2(x) #x
#define __to_string(x) __to_string2(x) // 生成不同个数的顺序符号
#define __repeat_0(m, ...)
#define __repeat_1(m, ...) __repeat_0(m, __VA_ARGS__) m(1, __VA_ARGS__)
#define __repeat_2(m, ...) __repeat_1(m, __VA_ARGS__) m(2, __VA_ARGS__)
#define __repeat_3(m, ...) __repeat_2(m, __VA_ARGS__) m(3, __VA_ARGS__)
#define __repeat_4(m, ...) __repeat_3(m, __VA_ARGS__) m(4, __VA_ARGS__)
#define __repeat_5(m, ...) __repeat_4(m, __VA_ARGS__) m(5, __VA_ARGS__)
#define __repeat_6(m, ...) __repeat_5(m, __VA_ARGS__) m(6, __VA_ARGS__)
#define __repeat_7(m, ...) __repeat_6(m, __VA_ARGS__) m(7, __VA_ARGS__)
#define __repeat_8(m, ...) __repeat_7(m, __VA_ARGS__) m(8, __VA_ARGS__)
#define __repeat_9(m, ...) __repeat_8(m, __VA_ARGS__) m(9, __VA_ARGS__)
#define __repeat_10(m, ...) __repeat_9(m, __VA_ARGS__) m(10, __VA_ARGS__)
#define __repeat_11(m, ...) __repeat_10(m, __VA_ARGS__) m(11, __VA_ARGS__)
#define __repeat_12(m, ...) __repeat_11(m, __VA_ARGS__) m(12, __VA_ARGS__)
#define __repeat_13(m, ...) __repeat_12(m, __VA_ARGS__) m(13, __VA_ARGS__)
#define __repeat_14(m, ...) __repeat_13(m, __VA_ARGS__) m(14, __VA_ARGS__)
#define __repeat_15(m, ...) __repeat_14(m, __VA_ARGS__) m(15, __VA_ARGS__) #define __last_repeat_0(m, ...)
#define __last_repeat_1(m, ...) m(1, __VA_ARGS__)
#define __last_repeat_2(m, ...) m(2, __VA_ARGS__)
#define __last_repeat_3(m, ...) m(3, __VA_ARGS__)
#define __last_repeat_4(m, ...) m(4, __VA_ARGS__)
#define __last_repeat_5(m, ...) m(5, __VA_ARGS__)
#define __last_repeat_6(m, ...) m(6, __VA_ARGS__)
#define __last_repeat_7(m, ...) m(7, __VA_ARGS__)
#define __last_repeat_8(m, ...) m(8, __VA_ARGS__)
#define __last_repeat_9(m, ...) m(9, __VA_ARGS__)
#define __last_repeat_10(m, ...) m(10, __VA_ARGS__)
#define __last_repeat_11(m, ...) m(11, __VA_ARGS__)
#define __last_repeat_12(m, ...) m(12, __VA_ARGS__)
#define __last_repeat_13(m, ...) m(13, __VA_ARGS__)
#define __last_repeat_14(m, ...) m(14, __VA_ARGS__)
#define __last_repeat_15(m, ...) m(15, __VA_ARGS__) #define __repeat(n, m_begin, m_end, ...) __connect(__repeat_, __cntdec(n))(m_begin, __VA_ARGS__) __connect(__last_repeat_, n)(m_end, __VA_ARGS__) // 基础工具宏结束
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Add IDispatch to class //////////////////////////////////////////////////////////////////////////
// 扩充CVarTypeInfo 模板类的定义
//template<>
//class CVarTypeInfo< void >
//{
//public:
// static const VARTYPE VT = VT_EMPTY;
// //static char VARIANT::* const pmField;
//};
template<typename T>
class CVarTypeInfoEx : public CVarTypeInfo<T>
{
public:
static HRESULT Assign(T& tDst, VARIANT* pSrc)
{
CComVariant v;
if (FAILED(v.ChangeType(VT, pSrc))) return DISP_E_BADVARTYPE;
#pragma warning(push)
#pragma warning(disable:4800)
tDst = v.*pmField;
#pragma warning(pop)
return S_OK;
}
static T Value(CComVariant& v)
{
return v.*pmField;
}
static bool ChangeType(CComVariant& vDst, VARIANT* pSrc)
{
return SUCCEEDED(vDst.ChangeType(VT, pSrc));
}
}; template<>
class CVarTypeInfoEx<VARIANT> : public CVarTypeInfo<VARIANT>
{
public:
static HRESULT Assign(VARIANT& tDst, VARIANT* pSrc)
{
return ::VariantCopy(&tDst, pSrc);
}
static VARIANT Value(CComVariant& v)
{
return v;
}
static bool ChangeType(CComVariant& vDst, VARIANT* pSrc) { return vDst=*pSrc, true; }
}; template<>
class CVarTypeInfoEx<CComVariant> : public CVarTypeInfoEx<VARIANT>
{
public:
static HRESULT Assign(CComVariant& tDst, VARIANT* pSrc)
{
tDst = *pSrc;
return S_OK;
}
static CComVariant Value(CComVariant& v)
{
return v;
}
}; //template<>
//class CVarTypeInfoEx<CComBSTR> : public CVarTypeInfoEx<BSTR>
//{
//public:
// static HRESULT Assign(CComBSTR& tDst, VARIANT* pSrc)
// {
// CComVariant v;
// if (FAILED(v.ChangeType(VT, pSrc))) return DISP_E_BADVARTYPE;
// tDst
//#pragma warning(push)
//#pragma warning(disable:4800)
// tDst = v.*pmField;
//#pragma warning(pop)
// return S_OK;
// }
// static CComBSTR Value(CComVariant& v)
// {
// return v.*pmField;
// }
//}; //////////////////////////////////////////////////////////////////////////
template<>
class CVarTypeInfo< bool >
{
public:
static const VARTYPE VT = VT_BOOL;
static VARIANT_BOOL VARIANT::* const pmField;
}; __declspec( selectany ) VARIANT_BOOL VARIANT::* const CVarTypeInfo< bool >::pmField = &VARIANT::boolVal; // 扩充CComBSTR 类型,用这种类型代替BSTR,能防止内存泄露或者内存释放错误
template<>
class CVarTypeInfo< CComBSTR >
{
public:
static const VARTYPE VT = VT_BSTR;
static BSTR VARIANT::* const pmField;
}; __declspec( selectany ) BSTR VARIANT::* const CVarTypeInfo< CComBSTR >::pmField = &VARIANT::bstrVal; // END of CVarTypeInfo. 使用者可以自行扩充新的类型,例如用CString来保存字符串
////////////////////////////////////////////////////////////////////////// // 定义多参数的模板类
//////////////////////////////////////////////////////////////////////////
// 可选参数模板类, #define __optparam(n, ...) typename T##n=int,
#define __optparam_end(n, ...) typename T##n=int
#define __optvalue(n, ...) T##n t##n=0,
#define __optvalue_end(n, ...) T##n t##n=0
#define __optswitch(n, ...) case n: return CComVariant(t##n); template<int nT=1, __repeat(15, __optparam, __optparam) __repeat(15, __optvalue, __optvalue_end) >
class _ParamsOpt
{
public:
static UINT Count() { return nT; }
static CComVariant DefaultValue(UINT index)
{
switch (index)
{
__repeat(15, __optswitch, __optswitch)
}
return CComVariant();
}
}; // 0个参数的特化模板
//template<>
class _ParamsOpt_0
{
public:
static UINT Count() { return 0; }
static CComVariant DefaultValue(UINT) { return CComVariant(); }
}; // 方法工具模板类和工具宏
#define __tparam(n, ...) typename T##n,
#define __tparam_end(n, ...) typename T##n
#define __param_type(n, ...) if (n<=dp->cArgs && !CVarTypeInfoEx<T##n>::ChangeType(v[n-1], &dp->rgvarg[dp->cArgs-n])) return E_INVALIDARG;
#define __funcparam(n, ...) CVarTypeInfoEx<T##n>::Value(n<=dp->cArgs ? v[n-1] : tOptions::DefaultValue(n-(Count()-tOptions::Count()))), //.*CVarTypeInfo<T##n>::pmField,
#define __funcparam_end(n, ...) CVarTypeInfoEx<T##n>::Value(n<=dp->cArgs ? v[n-1] : tOptions::DefaultValue(n-(Count()-tOptions::Count()))) //v[n-1].*CVarTypeInfo<T##n>::pmField
#define __funcparam_type(n, ...) T##n,
#define __funcparam_type_end(n, ...) T##n
#define __method_helper_t(n, ...) /
template<class TT, typename rettype, __repeat(n, __tparam, __tparam) class tOptions/*=_ParamsOpt_N<>*/, rettype (TT::* func)(__repeat(n, __funcparam_type, __funcparam_type_end)) > /
class _MethodHelper_##n /
{ /
public: /
static UINT Count() { return n; } /
static HRESULT CallMethod (LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult) /
{ /
if (pT==NULL) return E_FAIL; /
if (dp->cArgs < n-tOptions::Count()) return DISP_E_BADPARAMCOUNT; /
CComVariant v[n+1]; /*加是为了避免n==0 时的编译错误*/ /
__repeat(n, __param_type, __param_type) /
CComVariant vRet = (reinterpret_cast<TT*>(pT)->*func)( __repeat(n, __funcparam, __funcparam_end) ); /
if (pvarResult && vRet.vt!=VT_EMPTY) vRet.Detach(pvarResult); /
return S_OK; /
} /
}; /
/* 返回VOID的特化模板类*/ /
template<class TT, __repeat(n, __tparam, __tparam) class tOptions/*=OptionalParams<>*/, void (TT::* func)(__repeat(n, __funcparam_type, __funcparam_type_end)) > /
class _MethodHelper_##n<TT, void, __repeat(n, __funcparam_type, __funcparam_type) tOptions, func> /
{ /
public: /
static UINT Count() { return n; } /
static HRESULT CallMethod (LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult) /
{ /
if (pT==NULL) return E_FAIL; /
if (dp->cArgs < n-tOptions::Count()) return DISP_E_BADPARAMCOUNT; /
CComVariant v[n+1]; /*加是为了避免n==0 时的编译错误*/ /
__repeat(n, __param_type, __param_type) /
(reinterpret_cast<TT*>(pT)->*func)( __repeat(n, __funcparam, __funcparam_end) ); /
return S_OK; /
} /
}; // 预定义个方法调用工具模板类
__for_each_number(__method_helper_t) #define __defparamtype(n,...) int,
#define __defparamtype_end(n,...) int #define Params(...) __VA_ARGS__,
#define Params0()
//#define ParamsOpt(...) __VA_ARGS__
#define ParamsOpt1(...) __VA_ARGS__, _ParamsOpt<1, __VA_ARGS__, __repeat(14, __defparamtype, __defparamtype_end)
#define ParamsOpt2(...) __VA_ARGS__, _ParamsOpt<2, __VA_ARGS__, __repeat(13, __defparamtype, __defparamtype_end)
#define ParamsOpt3(...) __VA_ARGS__, _ParamsOpt<3, __VA_ARGS__, __repeat(12, __defparamtype, __defparamtype_end)
#define ParamsOpt4(...) __VA_ARGS__, _ParamsOpt<4, __VA_ARGS__, __repeat(11, __defparamtype, __defparamtype_end)
#define ParamsOpt5(...) __VA_ARGS__, _ParamsOpt<5, __VA_ARGS__, __repeat(10, __defparamtype, __defparamtype_end)
#define ParamsOpt6(...) __VA_ARGS__, _ParamsOpt<6, __VA_ARGS__, __repeat(9, __defparamtype, __defparamtype_end)
#define ParamsOpt7(...) __VA_ARGS__, _ParamsOpt<7, __VA_ARGS__, __repeat(8, __defparamtype, __defparamtype_end)
#define ParamsOpt8(...) __VA_ARGS__, _ParamsOpt<8, __VA_ARGS__, __repeat(7, __defparamtype, __defparamtype_end)
#define ParamsOpt9(...) __VA_ARGS__, _ParamsOpt<9, __VA_ARGS__, __repeat(6, __defparamtype, __defparamtype_end)
#define ParamsOpt10(...) __VA_ARGS__, _ParamsOpt<10, __VA_ARGS__, __repeat(5, __defparamtype, __defparamtype_end)
#define ParamsOpt11(...) __VA_ARGS__, _ParamsOpt<11, __VA_ARGS__, __repeat(4, __defparamtype, __defparamtype_end)
#define ParamsOpt12(...) __VA_ARGS__, _ParamsOpt<12, __VA_ARGS__, __repeat(3, __defparamtype, __defparamtype_end)
#define ParamsOpt13(...) __VA_ARGS__, _ParamsOpt<13, __VA_ARGS__, __repeat(2, __defparamtype, __defparamtype_end)
#define ParamsOpt14(...) __VA_ARGS__, _ParamsOpt<14, __VA_ARGS__, __repeat(1, __defparamtype, __defparamtype_end)
#define ParamsOpt15(...) __VA_ARGS__, _ParamsOpt<15, __VA_ARGS__
#define ParamsOptDefValue(...) __VA_ARGS__ #define _method_helper(T, name, type, paramcnt, ...) _MethodHelper_##paramcnt<T,type,__VA_ARGS__,_ParamsOpt_0,&T::name>::CallMethod
//#define _method_helper_with_option2(T, name, type, paramcnt, opt, ...) _MethodHelper_##paramcnt<T,type,__VA_ARGS__,opt,&T::name>::CallMethod
//#define _method_helper_with_option(T, name, type, paramcnt, params, optparams, optdefvals) _MethodHelper_##paramcnt<T,type,params,optparams,_ParamsOpt<optparams,optdefvals>,&T::name>::CallMethod
#define _method_helper_with_option(T, name, type, paramcnt, params, optparams, optdefvals) _MethodHelper_##paramcnt<T,type,params optparams,optdefvals>,&T::name>::CallMethod //////////////////////////////////////////////////////////////////////////
// 属性GET工具模板类和工具宏 // 直接访问成员变量时采用这个模板
template<class T, class baseT/*=T*/, typename rettype, rettype baseT::* member>
class _GetHelper
{
public:
static HRESULT CallGet(LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult)
{
if (pT==NULL) return E_FAIL;
CComVariant vRet = reinterpret_cast<T*>(pT)->*member;
if (pvarResult) vRet.Detach(pvarResult);
return S_OK;
}
}; // 用户提供了Get函数时采用这个模板,在这种情况下,属性名称不需要跟成员变量名称一致。函数原型是HRESULT GetXXX(VARIANT*)
template<class T, HRESULT (T::* getfunc)(VARIANT*)>
class _GetFuncHelper
{
public:
static HRESULT CallGet(LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult)
{
if (pT==NULL) return E_FAIL;
if (pvarResult) return (reinterpret_cast<T*>(pT)->*getfunc)(pvarResult);
return S_OK;
}
}; // 对于有默认值的集合类(如colls(1)),必须使用函数方式,因为GET操作也会带参数。函数原型是HRESULT GetXXX(VARIANT index, VARIANT* pResult)
template<class T, HRESULT (T::* getvaluefunc)(VARIANT,VARIANT*)>
class _GetValueFuncHelper
{
public:
static HRESULT CallGet(LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult)
{
if (pT==NULL) return E_FAIL;
CComVariant vIndex;
if (dp->cArgs>0) vIndex = dp->rgvarg[dp->cArgs-1];
if (pvarResult) return (reinterpret_cast<T*>(pT)->*getvaluefunc)(vIndex, pvarResult);
return S_OK;
}
}; #define _get_helper(T, name, type) _GetHelper<T,T,type,&T::name>::CallGet
#define _getfunc_helper(T, name) _GetFuncHelper<T, &T::Get##name>::CallGet
#define _getvalue_helper(T, name) _GetValueFuncHelper<T, &T::Get##name>::CallGet #define _get_base_helper(T, name, baseT, baseName, type) _GetHelper<T,baseT,type,&baseT::baseName>::CallGet
//#define _getfunc_base_helper(T, name, baseclass) _GetFuncHelper<T, &T::baseclass::Get##name>::CallGet //////////////////////////////////////////////////////////////////////////
// 属性PUT工具模板类和工具宏 // 直接访问成员变量时采用这个模板
template<class T, class baseT/*=T*/, typename rettype, rettype baseT::* member>
class _PutHelper
{
public:
static HRESULT CallPut(LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult)
{
if (pT==NULL) return E_FAIL;
if (dp->cArgs != 1) return DISP_E_BADPARAMCOUNT;
return CVarTypeInfoEx<rettype>::Assign(reinterpret_cast<T*>(pT)->*member, dp->rgvarg);
// CComVariant v;
// if (FAILED(v.ChangeType(CVarTypeInfo<rettype>::VT, dp->rgvarg))) return DISP_E_BADVARTYPE;
//#pragma warning(push)
//#pragma warning(disable:4800)
// reinterpret_cast<T*>(pT)->*member = v.*CVarTypeInfo<rettype>::pmField;
//#pragma warning(pop)
// return S_OK;
}
}; // 用户提供了Set或Put函数时采用这个模板,在这种情况下,属性名称不需要跟成员变量名称一致。函数原型是HRESULT SetXXX(VARIANT*) 或HRESULT PutXXX(VARIANT*)
template<class T, HRESULT (T::* putfunc)(VARIANT*)>
class _PutFuncHelper
{
public:
static HRESULT CallPut(LPVOID pT, DISPPARAMS* dp, VARIANT* pvarResult)
{
if (pT==NULL) return E_FAIL;
if (dp->cArgs != 1) return DISP_E_BADPARAMCOUNT;
return (reinterpret_cast<T*>(pT)->*putfunc)(dp->rgvarg);
}
}; #define _put_helper(T, name, type) _PutHelper<T,T,type,&T::name>::CallPut
#define _putfunc_helper(T, name) _PutFuncHelper<T,&T::Put##name>::CallPut
#define _setfunc_helper(T, name) _PutFuncHelper<T,&T::Set##name>::CallPut #define _put_base_helper(T, name, baseT, baseName, type) _PutHelper<T,baseT,type,&baseT::baseName>::CallPut
//#define _put_base_helper(T, name, baseT, type) _put_base_map_helper(T,name,baseT,name,type) //_PutHelper<T,baseT,type,&baseT::name>::CallPut //////////////////////////////////////////////////////////////////////////
// 映射表工具模板类和映射宏
typedef HRESULT (* fnDispMethod)(LPVOID pT, DISPPARAMS* dp, VARIANT* pVarResult);
struct DispMethodData
{
LPCOLESTR name; // property or method name
DISPID dispid; // dispid
fnDispMethod pfnGet;
fnDispMethod pfnPut;
fnDispMethod pfnMethod;
}; // {276887CB-4F1A-468d-AF41-D03070C53E68}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_IDispHost = { 0x276887cb, 0x4f1a, 0x468d, { 0xaf, 0x41, 0xd0, 0x30, 0x70, 0xc5, 0x3e, 0x68 } }; MIDL_INTERFACE("276887CB-4F1A-468d-AF41-D03070C53E68")
IDispHost : public IUnknown
{
public:
virtual LPVOID STDMETHODCALLTYPE GetOwner() = 0;
}; template<class T, bool tManaged=false>
class DispProvider : public IDispatch, public IDispHost
{
private:
T* _owner;
ULONG _refcount; public:
DispProvider() : _owner(NULL), _refcount(0) {}
void SetOwner(T* owner) { _owner = owner; }
// IDispHost
STDMETHOD_(LPVOID, GetOwner)() { return _owner; } /* IDispatch Methods*/
STDMETHOD_(ULONG, AddRef)() { return tManaged ? ++_refcount : 2; }
STDMETHOD_(ULONG, Release)()
{
if(tManaged && --_refcount==0)
{
__if_exists(T::DeleteInstance){T::DeleteInstance(_owner);}
//delete this;
};
return tManaged ? _refcount : 1;
}
STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj)
{
if (!_owner) return E_UNEXPECTED;
if (!ppvObj) return E_POINTER;
*ppvObj = NULL;
if (IsEqualIID(iid, __uuidof(IUnknown)) ||
IsEqualIID(iid, __uuidof(IDispatch)))
*ppvObj = (IDispatch*)this;
else if (IsEqualIID(iid, IID_IDispHost))
*ppvObj = (IDispHost*)this;
if (*ppvObj)
{
((LPUNKNOWN)(*ppvObj))->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) { *pctinfo=0; return E_NOTIMPL; }
STDMETHOD(GetTypeInfo)(UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo **ppTInfo) { *ppTInfo = NULL; return E_NOTIMPL; }
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR ** rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
{
ATLASSERT(cNames == 1);
if (cNames != 1) return E_NOTIMPL;
if (!_owner) return E_UNEXPECTED; *rgDispId = DISPID_UNKNOWN;
const DispMethodData* pMap = T::__GetDispMapEntry(*rgszNames);
if (pMap)
return *rgDispId = pMap->dispid, S_OK;
return DISP_E_MEMBERNOTFOUND;
}
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT *pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
{
if (!_owner) return E_UNEXPECTED; LPVOID pVoid = _owner;
const DispMethodData* pMap = T::__GetDispMapEntry(NULL, &dispIdMember, &pVoid);
if (pMap)
{
//if ((wFlags&DISPATCH_PROPERTYGET) && dispIdMember==DISPID_VALUE && pMap->pfnGet)
// return pMap->pfnGet(_owner, pdispparams, pVarResult); fnDispMethod pfn = (wFlags&DISPATCH_METHOD) ? pMap->pfnMethod : (wFlags==DISPATCH_PROPERTYGET) ? pMap->pfnGet : pMap->pfnPut;
if (pfn)
return pfn(pVoid/*_owner*/, pdispparams, pVarResult);
}
return DISP_E_MEMBERNOTFOUND;
}
}; //////////////////////////////////////////////////////////////////////////
// 映射的类继承工具
#define __parent_map(n, ...) __if_exists(T##n::__GetDispMapEntry) { if (!p) p = T##n::__GetDispMapEntry(pName, pDispid); if (p) pVoid=(LPVOID)static_cast<T##n*>((T*)pVoid); }
#define __tparam16(n,...) typename T##n=int,
#define __tparam16_end(n,...) typename T##n=int template<class T, __repeat(15, __tparam16, __tparam16_end)>
class _ParentMapHelper
{
public:
static const DispMethodData* __GetParentsMap(LPCOLESTR pName, DISPID* pDispid, LPVOID* ppVoid)
{
LPVOID pVoid = NULL;
if (ppVoid) pVoid = *ppVoid;
const DispMethodData* p = NULL;
__repeat(15, __parent_map, __parent_map)
if (ppVoid) *ppVoid = pVoid;
return p;
}
}; ////////////////////////////////////////////////////////////////////////// // 如果希望合并基类的映射表,...应该列举出基类
#define Begin_Disp_Map(classname, ...) /
private: DispProvider<classname> __disp; /
public: /
virtual IDispatch* GetDispatch() { return __disp.SetOwner(this), (IDispatch*)&__disp; } /
static const DispMethodData* __GetDispMapEntry(LPCOLESTR pszByName=NULL/*find by name*/, DISPID* pByDispid=NULL/*find by dispid*/, LPVOID* ppVoid=NULL/*offset of parent*/) /
{ /
typedef classname owner_class; /
typedef _ParentMapHelper<classname, __VA_ARGS__> parent_map_class; /
static const DispMethodData __map_entry[] = { #define Begin_Auto_Disp_Map(classname, ...) /
private: DispProvider<classname, true> __disp; classname** __ext_ref; /
private: /*classname();*/ /
public: /
virtual IDispatch* GetDispatch() { return (IDispatch*)&__disp; } /
virtual void SetExternalRef(classname** ppref) { __ext_ref=ppref; } /
static void DeleteInstance(classname* p) { if (p && p->__ext_ref) *p->__ext_ref=NULL; delete p; } /
static HRESULT CreateInstance(IDispatch** ppDisp, classname** ppOwner=NULL, BOOL bDetach=FALSE) /
{ /
if (ppOwner) *ppOwner = NULL; /
if (ppDisp==NULL) return E_POINTER; /
*ppDisp = NULL; /
classname* pOwner = new classname; /
if (pOwner==NULL) return E_OUTOFMEMORY; /
pOwner->__ext_ref = NULL; /
pOwner->__disp.SetOwner(pOwner); /
if (!bDetach) pOwner->__disp.AddRef(); /
if (ppOwner) *ppOwner = pOwner; /
*ppDisp = (IDispatch*)&pOwner->__disp; /
return S_OK; /
} /
static const DispMethodData* __GetDispMapEntry(LPCOLESTR pszByName=NULL/*find by name*/, DISPID* pByDispid=NULL/*find by dispid*/, LPVOID* ppVoid=NULL/*offset of parent*/) /
{ /
typedef classname owner_class; /
typedef _ParentMapHelper<classname, __VA_ARGS__> parent_map_class; /
static const DispMethodData __map_entry[] = { #define Disp_PropertyGet(dispid, name, ...) /
{OLESTR(#name), dispid, /
__if_exists(owner_class::Get##name){_getfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Get##name){ /
__if_exists(owner_class::name){_get_helper(owner_class,name,__VA_ARGS__)} /
__if_not_exists(owner_class::name){NULL /
__pragma(message("WARNING: property '" #name "' can't be got, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
}, /
NULL, NULL}, #define Disp_PropertyGet_Base_Ex(dispid, name, baseclass, basename, ...) /
{OLESTR(#name), dispid, /
__if_exists(owner_class::Get##name){_getfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Get##name){ /
__if_exists(owner_class::basename){_get_base_helper(owner_class,name,baseclass,basename__VA_ARGS__)} /
__if_not_exists(owner_class::basename){NULL /
__pragma(message("WARNING: property '" #name "' can't be got, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
}, /
NULL, NULL}, #define Disp_PropertyGet_Base(dispid, name, baseclass, ...) Disp_PropertyGet_Base_Ex(dispid, name, baseclass, name, __VA_ARGS__) #define Disp_ValueGet(name, ...) /
{OLESTR(#name), DISPID_VALUE, /
__if_exists(owner_class::Get##name){_getvalue_helper(owner_class,name)} /
__if_not_exists(owner_class::Get##name){ /
__pragma(message("WARNING: property '" #name "' can't be got, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
}, /
NULL, NULL}, #define Disp_PropertyPut(dispid, name, ...) /* ...==type */ /
{OLESTR(#name), dispid, NULL, /
__if_exists(owner_class::Set##name){_setfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Set##name){ /
__if_exists(owner_class::Put##name){_putfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Put##name){ /
__if_exists(owner_class::name){_put_helper(owner_class,name,__VA_ARGS__)} /
__if_not_exists(owner_class::name){NULL /
__pragma(message("WARNING: property '" #name "' can't be put, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
} /
}, /
NULL}, #define Disp_PropertyPut_Base_Ex(dispid, name, baseclass, basename, ...) /* ...==type */ /
{OLESTR(#name), dispid, NULL, /
__if_exists(owner_class::Set##name){_setfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Set##name){ /
__if_exists(owner_class::Put##name){_putfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Put##name){ /
__if_exists(owner_class::basename){_put_base_helper(owner_class,name,baseclass,basename__VA_ARGS__)} /
__if_not_exists(owner_class::basename){NULL /
__pragma(message("WARNING: property '" #name "' can't be put, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
} /
}, /
NULL}, #define Disp_PropertyPut_Base(dispid, name, baseclass, ...) Disp_PropertyPut_Base_Ex(dispid, name, baseclass, name, __VA_ARGS__) #define Disp_Property(dispid, name, ...) /* ...==type */ /
{OLESTR(#name), dispid, /
__if_exists(owner_class::Get##name){_getfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Get##name){ /
__if_exists(owner_class::name){_get_helper(owner_class,name,__VA_ARGS__)} /
__if_not_exists(owner_class::name){NULL /
__pragma(message("WARNING: property '" #name "' can't be got, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
}, /
__if_exists(owner_class::Set##name){_setfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Set##name){ /
__if_exists(owner_class::Put##name){_putfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Put##name){ /
__if_exists(owner_class::name){_put_helper(owner_class,name,__VA_ARGS__)} /
__if_not_exists(owner_class::name){NULL /
__pragma(message("WARNING: property '" #name "' can't be put, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
} /
}, /
NULL}, #define Disp_Property_Base_Ex(dispid, name, baseclass, basename, ...) /* ...==type */ /
{OLESTR(#name), dispid, /
__if_exists(owner_class::Get##name){_getfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Get##name){ /
__if_exists(owner_class::basename){_get_base_helper(owner_class,name,baseclass,basename,__VA_ARGS__)} /
__if_not_exists(owner_class::basename){NULL /
__pragma(message("WARNING: property '" #name "' can't be got, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
}, /
__if_exists(owner_class::Set##name){_setfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Set##name){ /
__if_exists(owner_class::Put##name){_putfunc_helper(owner_class,name)} /
__if_not_exists(owner_class::Put##name){ /
__if_exists(owner_class::basename){_put_base_helper(owner_class,name,baseclass,basename,__VA_ARGS__)} /
__if_not_exists(owner_class::basename){NULL /
__pragma(message("WARNING: property '" #name "' can't be put, and will be ignored. FILE(" __FILE__ ") LINE(" __to_string(__LINE__) ")")) /
} /
} /
}, /
NULL}, #define Disp_Property_Base(dispid, name, baseclass, ...) Disp_Property_Base_Ex(dispid, name, baseclass, name, __VA_ARGS__) #define Disp_Method(dispid, name, type, paramcnt, ...) /
{OLESTR(#name), dispid, NULL, NULL, _method_helper(owner_class,name,type,paramcnt,__VA_ARGS__)}, #define Disp_Method_With_Option(dispid, name, type, paramcnt, params, opts, defvals) /
{OLESTR(#name), dispid, NULL, NULL, _method_helper_with_option(owner_class,name,type,paramcnt,params,opts,defvals)}, #define End_Disp_Map() /
{NULL, DISPID_UNKNOWN, NULL, NULL, NULL} /
}; /
if (pszByName==NULL && pByDispid==NULL) return __map_entry; /
for (int i=0; i<sizeof(__map_entry)/sizeof(__map_entry[0]) - 1; i++) /
{ /
if (pByDispid) /
{ /
if (__map_entry[i].dispid == *pByDispid) return &__map_entry[i]; /
} /
else /*if (pszByName)*/ /
{ /
if (lstrcmpiW(__map_entry[i].name, pszByName) == 0) return &__map_entry[i]; /
} /
} /
return parent_map_class::__GetParentsMap(pszByName, pByDispid, ppVoid); /
} #pragma warning(pop) #endif // __MACRO_H__

  

转:宏定义的极致发挥---让你的普通C++类轻松支持IDispatch自动化接口(二)的更多相关文章

  1. (转载)内联函数inline和宏定义

    (转载)http://blog.csdn.net/chdhust/article/details/8036233 内联函数inline和宏定义   内联函数的优越性: 一:inline定义的类的内联函 ...

  2. [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化

    [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化 // point_test.cpp : 知识点练习和测试,用于单步调试,跟 ...

  3. C/C++中宏定义#pragma once与 #ifndef的区别

    为了避免同一个文件被include多次,我们可以通过以下两种方式来进行宏定义: 1. #ifndef方式2. #pragma once方式 在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两 ...

  4. 深入理解UE4宏定义—— GENERATED_BODY

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/72834164 作者:car ...

  5. iOS 日常工作之常用宏定义大全

    转自:http://www.jianshu.com/p/213b3b96cafe 前言: 在工作中, 很多小伙伴都会在PCH文件定义一些常用的宏,但是又怕写这些简单的宏浪费时间,又有时候忘记怎么定义了 ...

  6. VC中预处理指令与宏定义详解

    刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...

  7. iOS日常工作之常用宏定义大全

    前言: 在工作中, 很多小伙伴都会在PCH文件定义一些常用的宏,但是又怕写这些简单的宏浪费时间,又有时候忘记怎么定义了怎么办?本人在工作中也是如此.所以在这里给大家分享一些常用的宏定义,喜欢的小伙伴可 ...

  8. 读书笔记 effective c++ Item 2 尽量使用const,枚举(enums),内联(inlines),不要使用宏定义(define)

    这个条目叫做,尽量使用编译器而不要使用预处理器更好.#define并没有当作语言本身的一部分. 例如下面的例子: #define ASPECT_RATIO 1.653 符号名称永远不会被编译器看到.它 ...

  9. C++程序设计基础(4)宏定义和内联

    1.知识点 1.1宏定义 (1)不带参数的宏定义 #define ERROR_MESSAGE -100 #define SECONDS_PER_DAY 60*60*60 (2)带参数宏定义,这种形式称 ...

随机推荐

  1. django+uwsgi+nginx 导出excel超时问题

    一.问题现象和日志报错 之前在项目实现了excel导入导出:django导入导出excel实践,之前一直稳定运行,突然得知导出用户信息时出现nginx错误报告: 查看nginx日志,报错信息如下所示: ...

  2. MySQL实战45讲学习笔记:第二十九讲

    一.引子 我在第25和27篇文章中,和你介绍了主备切换流程.通过这些内容的讲解,你应该已经很清楚了:在一主一备的双 M 架构里,主备切换只需要把客户端流量切到备库:而在一主多从架构里,主备切换除了要把 ...

  3. 图论问题(1) : hdu 1198

    题目转自hdu 1198,题目传送门 题目大意: 给你11种单位水管摆放位置,若上下或左右有水管连接则视为这两点相连. 最后让你求这些张图中有几个连通块. 解题思路: 本来觉得这道题很简单,不就一个建 ...

  4. [LeetCode] 153. Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...

  5. jenkins pipeline 复杂的发布流程

    1.参数化构建界面 2.交付流水线界面 3.脚本详解 #!groovy pipeline { //在任何可用的代理上执行Pipeline agent any //参数化变量,目前只支持[boolean ...

  6. rocketmq常用命令整理

    1. 启动namesrv和borker sh /opt/alibaba-rocketmq/bin/runserver.sh com.alibaba.rocketmq.namesrv.NamesrvSt ...

  7. 向github项目push代码后,Jenkins实现其自动构建

    配置Jenkins(添加Github服务器) 1.进入[系统管理] --> [系统设置] ,找到[Github] 2.添加Github服务器 这里需要github提供一个密钥文本,我们去gith ...

  8. Mysql select into outfile 命令

    [1]Mysql select into outfile命令 在Mysql中,与load data infile命令作用相反的一个命令是select into outfile命令 select int ...

  9. Mysql load data infile 命令导入含中文csv源数据文件 【错误代码 1300】

    [1]Load data infile 命令导入含中文csv源数据文件 报错:Invalid utf8 character string: '??֧' (1)问题现象 csv格式文件源数据: 导入SQ ...

  10. 前端学习:学习笔记(JS部分)

    前端学习:学习笔记(JS部分) 前端学习:JS学习总结(图解)    JS的简介 JS基本语法 JS内置对象 JS的函数 JS的事件 JS的BOM JS的DOM JS的简介 新建步骤 <body ...