IWebbrowser2中C++與JS交互主要處理IDispatch中的兩個接口
這裡主要是把需要調用JS函數給編一個號,為什麼函數要編號呢?建議看看COM的原理,大概是C++實現的COM調用機制主要是用的虛函數表,但是其他的腳本語言中並沒有這個玩意,其他腳本需要調用函數時,只能通過函數的ID來找到對應的函數。
那麼我們就來給我們需要的函數一一編號:
函數列表的聲明部分
struct _JS_FUNCTION { LPCTSTR lpName; DISPID id; UINT nArgcCount; HRESULT (CMyWebEventHandler::*FUN)(DISPID, DISPPARAMS*, VARIANT*); }; const _JS_FUNCTION funs[]= { { L"setAppState", DISPID_BASE+0, 4, &CMyWebEventHandler::OnGetAppState }, { L"OneClickInstall", DISPID_BASE+1, 5, &CMyWebEventHandler::OnOneClickInstall }, // { L"GetInstallState", DISPID_BASE+2, 1, &CMyWebEventHandler::OnGetInstallState }, { L"DownLoadFile", DISPID_BASE+2, 5, &CMyWebEventHandler::OnDownLoadFile }, { L"OpenSite", DISPID_BASE+3, 1, &CMyWebEventHandler::OnOpenSite }, };
STDMETHODIMP CMyWebEventHandler::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { if(cNames == 0 || rgszNames == NULL || rgszNames[0] == NULL || rgDispId == NULL) { return E_INVALIDARG; } for(int i = 0; i
2、Invoke
函數的調用過程發生在這裡。
這個接口傳來函數的調用的標識是函數ID,那麼只要是我們上面標識了的ID,我們就根據其中記錄的回調地址調用它的處理函數
STDMETHODIMP CMyWebEventHandler::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid,WORD wFlags, DISPPARAMS* pDispParams,VARIANT* pVarResult, EXCEPINFO* pExcepInfo,UINT* puArgErr ) { if ( dispIdMemberDISPID_BASE+4 ) return E_NOTIMPL; if ( pDispParams->cArgs!=funs[dispIdMember-DISPID_BASE].nArgcCount ) return E_INVALIDARG; for(UINT i = 0; i < pDispParams->cArgs; ++i) { if((pDispParams->rgvarg[i].vt & VT_BSTR) == 0) { return E_INVALIDARG; } } return (this->*(funs[dispIdMember-DISPID_BASE].FUN))(dispIdMember, pDispParams, pVarResult); }
另外IE裡的JS函數一定要寫在window.external上面。所以,需要返回對應的 this指針
HRESULT STDMETHODCALLTYPE CMyWebEventHandler::GetExternal( /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch ) { *ppDispatch=this; return S_OK; }
C++調用JS
首先是獲取函數對應的ID,然後還是Invoke傳入函數ID和對應的參數信息
bool ExecJsFun( const wstring& lpJsFun, const vector& params ) { if ( NULL == m_pWebBrowser2 ) return false; CComPtr pDoc; HRESULT hr = m_pWebBrowser2->get_Document(&pDoc); if ( FAILED(hr) ) return false; CComQIPtr pDoc2=pDoc; if ( NULL == pDoc2 ) return false; CComQIPtr pScript; hr = pDoc2->get_Script(&pScript); if ( FAILED(hr) ) return false; DISPID id = NULL; CComBSTR bstrFun(lpJsFun.c_str()); hr = pScript->GetIDsOfNames(IID_NULL, &bstrFun, 1, LOCALE_SYSTEM_DEFAULT, &id); if ( FAILED(hr) ) return false; DISPPARAMS dispParams; memset(&dispParams, 0, sizeof(DISPPARAMS)); int nParamCount = params.size(); if ( nParamCount > 0 ) { dispParams.cArgs =nParamCount; dispParams.rgvarg =new VARIANT[nParamCount]; for (int i=0; i Invoke(id, IID_NULL, 0, DISPATCH_METHOD, &dispParams, &vResult, &execInfo, &uArgError); delete[] dispParams.rgvarg; if ( FAILED(hr) ) return false; return true; }