jameshooo请进[来者都有分哈]

skyxie 2011-01-12 10:58:15
最近在做一个Win32的项目,要对WebBrowser控件的事件进行sink处理,但是不能用MFC,ATL等框架。
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 看看这种解决方法是否有什么隐患哈~ 谢谢~
...全文
289 33 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
skyxie 2011-01-14
  • 打赏
  • 举报
回复
3x 浆糊~
cmf41013 2011-01-13
  • 打赏
  • 举报
回复
其实我是mark一下的,但是又不想纯表,或者不懂、路过、膜拜之类的
cmf41013 2011-01-13
  • 打赏
  • 举报
回复
win32的项目,不能用atl、mfc框架,还要用com技术
我觉得win32项目如果界面不复杂还好点,否则的话会把精力花费在很多没什么实际用途的代码上面。

com也是一样,如果没有类库,纯sdk,写起来。。。。。

初学com,见笑了
weiym 2011-01-13
  • 打赏
  • 举报
回复
其实个人觉得在项目中用最原始简单的东西就好了,比如自己实现IDispatch接口,其实也不麻烦。
用N多自定义复杂的宏让会以后维护这个代码的人骂死,当然写库的除外。
ouyh12345 2011-01-13
  • 打赏
  • 举报
回复
weiym 2011-01-13
  • 打赏
  • 举报
回复
其实这个代码也不错,LZ可以参考下
http://blog.csdn.net/superarhow/archive/2006/09/20/1250270.aspx
sxqinge 2011-01-13
  • 打赏
  • 举报
回复
唉,我发现自己完全看不懂啊。。。。
Eleven 2011-01-13
  • 打赏
  • 举报
回复
膜拜一下~
见习学术士 2011-01-13
  • 打赏
  • 举报
回复
学习妖孽的代码
kemee 2011-01-13
  • 打赏
  • 举报
回复
不知道为什么,距离的差距让我很是绝望
bragi523 2011-01-13
  • 打赏
  • 举报
回复
确实很妖孽的代码
jameshooo 2011-01-13
  • 打赏
  • 举报
回复
看不见的裂痕 2011-01-13
  • 打赏
  • 举报
回复
jameshooo 还没来啊..占座
skyxie 2011-01-13
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 jameshooo 的回复:]
终于看到有人读这段代码了,而且完全读懂了,谢谢支持。
你的解决方法没错,我的代码中没有考虑到 VT_BYREF 的情况,仔细看了你修改的部分,完全可用。

事实上,我自己用的版本已经经过改进了,对于实在难以转换的属性类型,我提供了通用方法来解决,比如,如果某个属性(比如Name)的类型难以转换,可以不直接映射Name成员变量,而是实现一个HRESUTL GetName(VARIANT*)的方……
[/Quote]
能否把你完整的新版代码贴出来? 谢谢~

虽然我不喜欢有码 ^_^
这不是鸭头 2011-01-13
  • 打赏
  • 举报
回复
看了浆糊的代码,我表示鸭梨好大
sunlin7 2011-01-13
  • 打赏
  • 举报
回复
我来接分~~
快乐鹦鹉 2011-01-13
  • 打赏
  • 举报
回复
jameshooo 2011-01-13
  • 打赏
  • 举报
回复

// 旧版写法
#define Disp_PropertyGet(dispid, name, type) \
{OLESTR(#name), dispid, _get_helper(owner_class,name,type), NULL, NULL},

#define Disp_PropertyPut(dispid, name, type) \
{OLESTR(#name), dispid, NULL, _put_helper(owner_class,name,type), NULL},

#define Disp_Property(dispid, name, type) \
{OLESTR(#name), dispid, _get_helper(owner_class,name,type), _put_helper(owner_class,name,type), NULL},


// 新版写法
#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_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_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},



新版的几个改进之处:
1、如果不想直接提供成员作为属性,可以用成员函数的方式提供属性读写。
2、支持基类映射表,即如果基类也实现了映射表,派生类不用重复填表,自动合并基类表项。唯一的要求就是DISPID不要重复。
3、可以同时合并多个基类映射表。
4、添加可选参数支持,比如某个方法有5个参数,后3个为可选参数(有默认值),那么调用者可以只用2个参数来调用。
5、添加DISPID_VALUE支持,类似于VB中的对象默认属性。
jameshooo 2011-01-13
  • 打赏
  • 举报
回复
终于看到有人读这段代码了,而且完全读懂了,谢谢支持。
你的解决方法没错,我的代码中没有考虑到 VT_BYREF 的情况,仔细看了你修改的部分,完全可用。

事实上,我自己用的版本已经经过改进了,对于实在难以转换的属性类型,我提供了通用方法来解决,比如,如果某个属性(比如Name)的类型难以转换,可以不直接映射Name成员变量,而是实现一个HRESUTL GetName(VARIANT*)的方法即可完成属性的读取,实现 HRESULT PutName(VARIANT*) 完成属性设置,如何转换完全自己说了算,宏里面自动判断,如果实现了这个名称的函数就用函数,没实现就直接用成员。不过还是没考虑 VT_BYREF 的情况。

如果需要新版代码,我可以贡献出来。
向立天 2011-01-13
  • 打赏
  • 举报
回复
我是来看jameshooo的
呵呵
加载更多回复(1)

3,248

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧