如何实现IE中JS和VC之间的互相调用

别来无恙 提交于 2020-02-10 02:56:34

一直做IE相关的东西,但是发现对JS和VC之间如何调用不是很明白。虽然知道通过IDispatch接口可以在VC程序和JS之间进行交互,但是如何具体做一直有点模糊,所以就专门做了个实验,看看他们到底如何进行沟通。

脚本语言和编译型语言之间进行通信是通过IDispatch接口来行的,这里我对双接口的理论就不进行讨论,直接看看如何用WTL代码来实现。

首先定义如下的一个IDispatch实现:

 1 class CExternalDisp: 2     public CComObjectRoot, 3     public IDispatch 4 { 5 public: 6     CExternalDisp(void); 7     ~CExternalDisp(void); 8  9     BEGIN_COM_MAP(CExternalDisp)10         COM_INTERFACE_ENTRY(IDispatch)11     END_COM_MAP()12 13      HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 14     /* [out] */ UINT *pctinfo) 15     {16         return E_NOTIMPL;17     }18 19     HRESULT STDMETHODCALLTYPE GetTypeInfo( 20         /* [in] */ UINT iTInfo,21         /* [in] */ LCID lcid,22         /* [out] */ ITypeInfo **ppTInfo)23     {24         return E_NOTIMPL;25     }26 27     virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 28         /* [in] */ REFIID riid,29         /* [size_is][in] */ LPOLESTR *rgszNames,30         /* [in] */ UINT cNames,31         /* [in] */ LCID lcid,32         /* [size_is][out] */ DISPID *rgDispId)33     {34         CComBSTR bsName(*rgszNames);35         if (bsName == L"abc")36         {37             *rgDispId = 2535;38             return S_OK;39         }40         return E_NOTIMPL;41 42     }43 44     virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 45         /* [in] */ DISPID dispIdMember,46         /* [in] */ REFIID riid,47         /* [in] */ LCID lcid,48         /* [in] */ WORD wFlags,49         /* [out][in] */ DISPPARAMS *pDispParams,50         /* [out] */ VARIANT *pVarResult,51         /* [out] */ EXCEPINFO *pExcepInfo,52         /* [out] */ UINT *puArgErr) 53     {54         if (dispIdMember == 2535)55         {56             for (int i = 0; i < pDispParams->cArgs; ++i)57             {58                 if( pDispParams->rgvarg[i].vt == VT_INT)59                     i = i;60                 else61 62                     i = i;63 64             }65 66 67             MessageBox(NULL, L"sdjlkf", L"sdl", MB_OK);68             return S_OK;69         }70         return E_NOTIMPL;71     }72 73 };

以上代码中定义了一个CExternalDisp的组件,实现了IDispatch接口,当js脚本语言调用对象的某个方法时,会转成通过IDispatch的Invoke函数来调用,不同的函数对应不同的dispIdMember,而这个数字又是通过GetIDsOfNames来得到的。

有了CExternalDisp这个组件,还需要将其注册成为IE的exteranl对象。在IE控件的初始化部分进行设置,代码如下:

1     CComPtr<IWebBrowser2> spWeb;2     HRESULT hr = m_view.QueryControl(IID_IWebBrowser2, (void**)&spWeb );3     CComObject<CExternalDisp> *obj;4     CComObject<CExternalDisp>::CreateInstance(&obj);5     CComPtr<IDispatch> spDisp;6     obj->QueryInterface(IID_IDispatch, (void**)&spDisp);7     m_view.SetExternalDispatch(spDisp);

这样,JS脚本中的代码就可以访问window.external对象中得方法了。下面是html中js调用exteranl.abc的代码段:

<HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 8.0"><TITLE></TITLE><script type="text/javascript">    window.external.abc(1, 'ljw', 2.3);</script></HEAD><BODY></BODY></HTML>

可以看到在页面加载时调用了window.external.abc(1, 'ljw', 2.3);这个方法,还传递了参数。 当js的执行引擎解释这个语句时,会先去讲abc这个字符串送到GetIDsOfNames中去,获得对应的DISPID, 然后用这个DISPID在调用Invoke函数。我们在invoke函数对这个abc方法对应的dispid进行了处理,就能够给js进行结果反馈。通过实验,js函数中得参数是放在DISPPARAMS中传入Invoke的,而且好像是最右边的参数最先入栈。



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!