一点编写 BHO 的思路,求指点

hbs_biscuit 2011-09-24 03:25:01
大家好:
我写了一个BHO ,现在能做到的是 BHO 可以直接执行 IE 里面的 JS 方法。
同时我以如下方式 为 IE 的 IHTMLWindow 插入了一个我自己写的 IDispatch 对象
CComQIPtr<IHTMLDocument2> spDocument2 = spDisp;
CComPtr<IHTMLWindow2> spWin;
hr = spDocument2->get_parentWindow(&spWin);
if(SUCCEEDED(hr))
{
hr = spWin->QueryInterface(IID_IDispatchEx, (void **)&spDispEx);
DISPID dispid;
hr = spDispEx->GetDispID(CComBSTR("phonePlugInIE"),fdexNameEnsure,&dispid);
DISPPARAMS dispparams;
dispparams.rgvarg = new VARIANT;
//dispparams.rgvarg= new CComVariant("HELLO WORLD OBJECT");
DISPID dispidPut=DISPID_PROPERTYPUT;
dispparams.rgdispidNamedArgs=&dispidPut;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
IDispatch* dispatchPtr( this );
//IDispatch* phoneActionDisp;
//hr=pphoneConnector->pphoneAction->QueryInterface(IID_IDispatch,(void**)&phoneActionDisp);
//IDispatch* dispatchPtr(phoneActionDisp);
// dispatchPtr->GetIDsOfNames()
dispparams.rgvarg->pdispVal = dispatchPtr;
dispparams.rgvarg->vt = VT_DISPATCH;
VARIANT temp;
HRESULT result = spDispEx->InvokeEx( dispid, LOCALE_USER_DEFAULT ,
DISPATCH_PROPERTYPUT,
&dispparams , &temp , NULL , NULL );


这样使得我可以在 IE 的 JS 中直接以如下方式调用
window.phonePlugInIE.xxxmethod() 的方式调用 BHO 的功能

更进一步的想法:
如果我插入的 phonePlugInIE 对象可以 有 COM 事件放出来,那么我如何使用 JS 方便的接收呢。

bho 直接调用JS 方法的实现就不用谈了,我已经实现了,但是感觉有点儿绕。 我想让JS 相应我的对象的事件 ,就像 相应一个button 的OnClick 那样简单。

求指点
...全文
560 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
hbs_biscuit 2012-05-24
  • 打赏
  • 举报
回复
为公司做的东西,所以发不了代码,有问题可以共同研究
Q595655989 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
大家好:
我写了一个BHO ,现在能做到的是 BHO 可以直接执行 IE 里面的 JS 方法。
同时我以如下方式 为 IE 的 IHTMLWindow 插入了一个我自己写的 IDispatch 对象
C/C++ code
CComQIPtr<IHTMLDocument2> spDocument2 = spDisp;
CComPtr<IHTMLWindow2> spWin;
……
[/Quote]

最近也在接触这方面的问题,lz能不能发个全的代码?刚开始学习不久,谢谢。
hbs_biscuit 2011-10-21
  • 打赏
  • 举报
回复
好久没有上CSDN ,汇报一下,这个问题我已经解决了 。

其实说起来很简单。

1. 在BHO 中实现一个 对象
2. 在BHO 初始化的时候就实例化这个对象,保证IE 解释页面的时候就可以找到这个对象
3. 当IE 就绪后,直接通过 DOCMENT2 接口找到 父窗口,然后将我们自己创建的对象 作为一个属性注入
4. 这样 JS 就可以直接操纵这个对象,以及相应这个对象的事件了。

注意要点:
1. 对象要继承 两个接口
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
要实现 IProvideClassInfo2接口,如果使用ATL 的话,有现成的模板可以继承,
如下:
class ATL_NO_VTABLE CPhoneObject :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CPhoneObject, &CLSID_PhoneObject>,
public IConnectionPointContainerImpl<CPhoneObject>,
public CProxy_IPhoneObjectEvents<CPhoneObject>,
public IDispatchImpl<IPhoneObject, &IID_IPhoneObject, &LIBID_phonePlugInIELib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IProvideClassInfo2Impl<&CLSID_PhoneObject,&DIID__IPhoneObjectEvents>

2. 对象一定要在页面载入之前创建,不然IE 在调用JS 引擎的时候这个对象还没创建,那么JS 引擎自己创建一个同名的对象,这样就和我们自己的对象没有什么关系了
创建对象可以采用如下方式:
hr=CComObject<CPhoneObject>::CreateInstance(&pPhoneObject);
3. 这个对象一定要作为一个 属性 注入到 IHTMLWindow2 中,这样JS 引擎才能解析这个对象。
获得 IHTMLWindow2 可以使用如下方法
CComPtr<IHTMLWindow2> spWin;
//获得IHTMLWindow2接口
hr = spDocument2->get_parentWindow(&spWin);
对象注入使用如下代码,供参考:
m_spWebBrowser->get_Document(&spDisp);//获得IHTMLDocument2对象的IDispatch接口

if(spDisp == NULL)
{
return;
}
CComQIPtr<IHTMLDocument2> spDocument2 = spDisp;
CComPtr<IHTMLWindow2> spWin;
//获得IHTMLWindow2接口
hr = spDocument2->get_parentWindow(&spWin);
if(SUCCEEDED(hr))
{
//查询到IHTMLWindow2的IDispatchEx
hr = spWin->QueryInterface(IID_IDispatchEx, (void **)&spDispEx);
DISPID dispid;
//按名称获得 DISPID ,如果没有则创建一个新的DISPID 返回
hr = spDispEx->GetDispID(CComBSTR("phonePlugInIE"),fdexNameEnsure,&dispid);
DISPPARAMS dispparams;
dispparams.rgvarg = new VARIANT;
DISPID dispidPut=DISPID_PROPERTYPUT;
dispparams.rgdispidNamedArgs=&dispidPut;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
//检查对象是否已经创建了,如果没有创建则创建之
if(!pPhoneObject)
{
hr=CComObject<CPhoneObject>::CreateInstance(&pPhoneObject);
}
//准备参数进行InvokeEx调用
IDispatch* dispatchPtr( pPhoneObject );
dispparams.rgvarg->pdispVal = dispatchPtr;
dispparams.rgvarg->vt = VT_DISPATCH;
VARIANT temp;
HRESULT result = spDispEx->InvokeEx( dispid, LOCALE_USER_DEFAULT ,
DISPATCH_PROPERTYPUT,
&dispparams , &temp , NULL , NULL );
return;
}

4 . 如果你的 JS 也是动态LOAD 的话,同时如果自己提供的对象需要频繁的动态加载和反加载到IE 中的话,那注意在JS代码段 加上 <defer> 参数,因为系统运行起来之后 对象的创建时机和JS引擎的解析,在时序上不可控。

5. 对于我们的这个对象,你可以像调用 js中 window 对象的缺省属性和方法一样调用。
例: 你可以使用 window.phonePlugInIE.method1(xxx),
也可以使用phonePlugInIE.method1(xxx)
从本质上 我们的这个对象已经是 htmlwindow 对象的一个 属性了(或者说是一个htmlwindow 类的成员)

6. 由于我们的对象实现了 事件,同时实现了 provideclassinfo2,所以JS 引擎在解析我们的对象的时候也能解析到我们可以公开的事件( 曾经有资料说JS 不能实现事件,我本人在此方面有过很大的认识误区,认为JS 不能获得动态对象的事件,实际上这件事情是不同的,也就是说 ,如果我们用非JS 语言创建的对象,如果这个对象有事件的话 JS 是可以捕获的,如果这个对象是 JS 创建的,那么这个对象没有办法创建事件,所以JS 也无从捕获 这个JS 对象的事件。这是我经过很大的弯路以后自己的理解,有不同之处可以继续讨论)

在JS 中捕获 对象的事件有多种方式,大家可以参考 maquan 同学以前的一些帖子:
如 :
function window.phonePlugInIE::Event1()
function window.phonePlugInIE::Event1()
function phonePlugInIE.Event1()
function window.phonePlugInIE.Event1()
都可以正常捕获。

有异议和问题的话可以 邮件我继续讨论 igrasping@163.com
或者在 http://hi.csdn.net/hbs_biscuit 留言。



最后感谢 maquan ,你的帖子给了我很多思路和灵感!!
maquan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 hbs_biscuit 的回复:]
可能我说的不是太明白:
我的这个组件不是 通过 js 中的 ActiveXObject创建
或者 <object progid=xxxxx 标签创建
我这个组件是动态 附加到 ie 中 window(或者说是 IHTMLWindow2) 对象上的。
按你
var window.phonePlugInIE::jsmethod() {
// dosomething
}
的方法试了以下,好像不行---------ps 我知道这种方式 如果phonePlugInIE是ActiveXObject创建出来的对象的话是可以的[/Quote]
这种写法完全可以,关键的一点是要确保“该段代码在被解析的时候,目标对象已经存在”,比如以下几种情况:

1. 如果你的 COM 是通过 new AcriveXObject() 方式动态创建的,那么,这段 script 要写在 new 的后面。

2. 如果你是用 <object> 标签静态嵌入的,那么这段 script 在 HTML 中的位置就要写在 <object> 标签后面。

3. 对于第 2 种情况,如果你一定要把 <script> 写在靠前的位置,也可以考虑 <script defer>


————————————————————————————————
基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
maquan 2011-09-27
  • 打赏
  • 举报
回复
要想让 COM 对象(比如 PhonePlugInIE)成为一个“事件源”,标准的做法是:

1. 在 TypeLib 里(一般是 .idl)为 PhonePlugInIE 声明一个呼出接口:
[default, source] dispinterface _DPhonePlugInIEEvents;


2. 当然,你还得在 TypeLib 里定义 _DPhonePlugInIEEvents 这个接口,但不需要实现它。这其中包含了你需要的事件(一个 method)。

3. 给 PhonePlugInIE 实现 IConnectionPointContainer 这个接口,让 COM 容器(比如 IE)把它将要挂接的 event sink 传给你。

4. 在实现 IConnectionPointContainer 的时候你会发现,可能同时还需要实现 IEnumConnectionPoints / IConnectionPoint / IEnumConnections。

5. 当你需要触发事件的时候,在你得到的 event sink 对象身上通过 _DPhonePlugInIEEvents 调用你定义的 method。

如果是用 MFC 的话,其中 3 - 5 最简单的办法就是从 COleControl 派生。


————————————————————————————————
基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
hbs_biscuit 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 redui 的回复:]

引用 8 楼 hbs_biscuit 的回复:

to redui:
在bho 中如何调用呢, 使用 事件连接点的方式吗


BHO不需要任何调用,你的组件已经被JS获得了,你的组件实现连接点,包含 jsmethod 方法,在JS里直接写上述代码就能被事件调用到。这个事件什么时候触发,那是你组件要做的事情,跟BHO无关
[/Quote]

可能我说的不是太明白:
我的这个组件不是 通过 js 中的 ActiveXObject创建
或者 <object progid=xxxxx 标签创建
我这个组件是动态 附加到 ie 中 window(或者说是 IHTMLWindow2) 对象上的。
按你
var window.phonePlugInIE::jsmethod() {
// dosomething
}
的方法试了以下,好像不行---------ps 我知道这种方式 如果phonePlugInIE是ActiveXObject创建出来的对象的话是可以的
W1nds 2011-09-26
  • 打赏
  • 举报
回复
学习了,最近看AX相关的东西很头痛啊
hbs_biscuit 2011-09-25
  • 打赏
  • 举报
回复
to gameslq:
你的文章实现了bho响应i话题ihtmlwindow2的默认事件

我的意思是已经在一个bho中写了一个idisatch对象,而且js也能直接调用这个对象了,
问题是js有办法接收这个对象的事件吗?
redui 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hbs_biscuit 的回复:]

to redui:
在bho 中如何调用呢, 使用 事件连接点的方式吗
[/Quote]

BHO不需要任何调用,你的组件已经被JS获得了,你的组件实现连接点,包含 jsmethod 方法,在JS里直接写上述代码就能被事件调用到。这个事件什么时候触发,那是你组件要做的事情,跟BHO无关
gameslq 2011-09-25
  • 打赏
  • 举报
回复
我想让JS 相应我的对象的事件 ,就像 相应一个button 的OnClick 那样简单。

请参考这个
http://blog.csdn.net/lyclowlevel/article/details/5955065。
hbs_biscuit 2011-09-25
  • 打赏
  • 举报
回复
按上一贴的想法 写了一下测试代码

发现 直接 invoke DISPID 为 0 的时候,是可以调用的

但是有一个问题 ,为什么 使用 attachEvent(IDispath* pObj); 传入的指针 做GetIDsOfNames 调用返回的是S_FALSE 呢, GetIDsOfNames 不能返回 DISPID=0 的那个方法吗 ?
oyljerry 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hbs_biscuit 的回复:]
to redui:
在bho 中如何调用呢, 使用 事件连接点的方式吗
[/Quote]
连接点就是callback
hbs_biscuit 2011-09-25
  • 打赏
  • 举报
回复
如果我在 我建立的对象中 直接公布一个函数
attachEvent(IDispath* pObj);
然后在 js 中调用window.phonePlugInIE.attachEvent(jsmethod);

js 中写一个函数
var jsmethod()
{
}

这样调用可以吗

我怎样在bho 中 以 idispatch 接口 invoke 的方式调用 js函数呢
hbs_biscuit 2011-09-25
  • 打赏
  • 举报
回复
to redui:
在bho 中如何调用呢, 使用 事件连接点的方式吗
redui 2011-09-25
  • 打赏
  • 举报
回复
var window.phonePlugInIE::jsmethod() {
// dosomething
}
oyljerry 2011-09-24
  • 打赏
  • 举报
回复
貌似只有直接调用JS来实现类似JS 事件响应.

3,248

社区成员

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

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