google之后,用到了您的:
宏定义的极致发挥---让你的普通C++类轻松支持IDispatch自动化接口
非常感谢您提供的这段妖孽的代码!!!为我节省了大量的时间 ^_^
不过在用于sink WebBrowser控件的事件时,发现有2个问题:
(我的环境: Windows XP + VS2008 sp1)
以处理 BeforeNavigate2 为例:
void BeforeNavigate2(
IDispatch *pDisp,
VARIANT *url,
VARIANT *Flags,
VARIANT *TargetFrameName,
VARIANT *PostData,
VARIANT *Headers,
VARIANT_BOOL *Cancel
)
Begin_Disp_Map(WebPageFilter)
Disp_Method(DISPID_BEFORENAVIGATE2, BeforeNavigate2, void, 7, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT_BOOL *)
End_Disp_Map()
VS2008没有定义class CVarTypeInfo< LPVARIANT >,需要自己定义(这不是问题)
template<>
class CVarTypeInfo< LPVARIANT >
{
public:
static const VARTYPE VT = VT_BYREF|VT_VARIANT;
static LPVARIANT VARIANT::* const pmField;
};
__declspec( selectany ) LPVARIANT VARIANT::* const CVarTypeInfo< LPVARIANT >::pmField = &VARIANT::pvarVal;
问题1)
定义了CVarTypeInfo< LPVARIANT >之后,对VT_BYREF|VT_VARIANT,在执行到ChangeType时仍然会出错
#define __param_type(n, ...) if (FAILED(v[n-1].ChangeType(CVarTypeInfo<T##n>::VT, &dp->rgvarg[dp->cArgs-n])))
问题2)
对VARIANT_BOOL * (VT_BYREF | VT_BOOL)
VARIANT_BOOL * 即short* ,
而VS2008定义了CVarTypeInfo< short* >但是VT不是VT_BYREF | VT_BOOL
template<>
class CVarTypeInfo< short* >
{
public:
static const VARTYPE VT = VT_I2|VT_BYREF;
static short* VARIANT::* const pmField;
};
__declspec( selectany ) short* VARIANT::* const CVarTypeInfo< short* >::pmField = &VARIANT::piVal;
我使用的解决方法:
1)
将__param_type中的CComVariant::ChangeType改为使用CComVariant::Copy
#define __param_type(n, ...) \
do \
{ \
if( CVarTypeInfo<T##n>::VT != dp->rgvarg[dp->cArgs-n].vt) {return E_INVALIDARG;} \
HRESULT hr = v[n-1].Copy(&dp->rgvarg[dp->cArgs-n]); \
if (FAILED(hr)) \
{ \
TRACE(_T("arg%d, Copy VARIANT failed!(type:0x%x,\n"), n, CVarTypeInfo<T##n>::VT); \
return E_INVALIDARG; \
} \
} while (0);
2)
定义VARIANT_BOOL *的包装类来解决VT不匹配的问题, BeforeNavigate2的参数也要相应修改
class VARIANT_BOOL_POINTER_WAPPER
{
public:
VARIANT_BOOL_POINTER_WAPPER(VARIANT_BOOL * pBool){ p = pBool; }
VARIANT_BOOL * p;
};
class CVarTypeInfo< VARIANT_BOOL_POINTER_WAPPER >
{
public:
static const VARTYPE VT = VT_BYREF|VT_BOOL;
static VARIANT_BOOL * VARIANT::* const pmField;
};
__declspec( selectany ) VARIANT_BOOL * VARIANT::* const CVarTypeInfo<VARIANT_BOOL_POINTER_WAPPER>::pmField = &VARIANT::pboolVal;
Begin_Disp_Map(WebPageFilter)
Disp_Method(DISPID_BEFORENAVIGATE2, BeforeNavigate2, void, 7, IDispatch*, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT_BOOL_POINTER_WAPPER)
End_Disp_Map()
void WebPageFilter::BeforeNavigate2(
//VARIANT *pDisp,
IDispatch *pDisp,
VARIANT *url,
VARIANT *Flags,
VARIANT *TargetFrameName,
VARIANT *PostData,
VARIANT *Headers,
VARIANT_BOOL_POINTER_WAPPER Cancel
)
{
TRACE(_T("WebPageFilter::BeforeNavigate2\n"));
VARIANT_BOOL * pCancel = Cancel.p;
*pCancel = VARIANT_TRUE; //能生效
}
请 jameshooo 看看这种解决方法是否有什么隐患哈~ 谢谢~