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; iInvoke(id, IID_NULL, 0, DISPATCH_METHOD, &dispParams, &vResult, &execInfo, &uArgError);
delete[] dispParams.rgvarg;
if ( FAILED(hr) )
return false;
return true;
}