0

本文演示了使用COM组件调用网页javascript的两种方法,第一种方法无法获取javascript的返回值,方法比较简单;第二种方法需要MSHTML库的支持,可以获取Javascript的返回值。

假设javascript代码如下:

复制代码
function add(str)
{
    var o;
    o = $("test");
    o.innerHTML += "<span>" + str + "</span>"
    return "helloworld!";
}
复制代码

第一种方法的原理是采用IHTMLWindow2接口的execScript来调用,获取IHTMLWindow2接口可以使用IHTMLDocument2接口的get_parentWindow方法,获取IHTMLDocument2接口可以使用CDHtmlDialog的GetDHtmlDocument方法。具体代码如下:

复制代码
 1     IHTMLDocument2* pDocument;
 2     IHTMLWindow2* pWindow;
 3 
 4     HRESULT hr = GetDHtmlDocument(&pDocument);
 5     
 6     ASSERT(SUCCEEDED(hr));
 7 
 8     hr = pDocument->get_parentWindow(&pWindow);
 9     CComBSTR bstrScriptName = TEXT("add('test');");
10 
11     CComVariant ret;            // 这个ret变量其实不能获取javascript的返回值
12 
13     ret.ChangeType(VT_EMPTY);
14     hr = pWindow->execScript(bstrScriptName, L"Javascript", &ret);
15 
16     if (FAILED(hr))
17     {
18         CComBSTR bstrErrorInfo;
19         IErrorInfoPtr errPtr;
20 
21         GetErrorInfo(0, &errPtr);
22         errPtr->GetDescription(&bstrErrorInfo);
23 
24         AfxMessageBox(bstrErrorInfo);
25     }
复制代码

第二种方法采用InvokeHelper方法来调用,代码如下:

复制代码
 1     IHTMLDocument2 *pDocument;
 2     HRESULT hr = GetDHtmlDocument(&pDocument);
 3 
 4     MSHTML::IHTMLDocument2Ptr spDoc(pDocument);
 5     IDispatchPtr spDisp(spDoc->GetScript());
 6     
 7     if (spDisp)
 8     {
 9         OLECHAR FAR *szMember = L"add";
10         DISPID dispid;
11         CComVariant varRet;
12         static BYTE params[] = VTS_BSTR;
13 
14         hr = spDisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
15         COleDispatchDriver dispDriver(spDisp, FALSE);
16         dispDriver.InvokeHelper(dispid, DISPATCH_METHOD, VT_VARIANT, &varRet, params, L"test");
17 
18         varRet.ChangeType(VT_BSTR);
19         AfxMessageBox(TEXT("返回值是:") + CString(varRet.bstrVal));
20     }

------------------------------------------------------------------------------------
VC调用javascript:
第一种:通过execScript调用。这种方法,虽然操作方便,但不能获取返回值。
m_spHtmlDoc->get_parentWindow(&m_pHtmlWindow);
VARIANT ret;
ret.vt = VT_EMPTY;
BSTR bstr = sScript.AllocSysString();
bRet = m_pHtmlWindow->execScript(bstr, L"javascript", &ret);
::SysFreeString(bstr);
sRet = CString(ret);

第二种:先用GetIDsOfNames找到这个脚本函数名称,然后再调用。这种方法可以返回结果,有返回值。但是无法调用js的系统函数,如eval。
BOOL CDhtmlDlgWindow::CallJScript(const CString strFunc, const CStringArray& paramArray, CComVariant* pVarResult)
{
    CComPtr spScript;
    if (NULL==m_spHtmlDoc)
    {
        return FALSE;
    }
    HRESULT hr;
    hr = m_spHtmlDoc->get_Script(&spScript);
    if(!SUCCEEDED(hr))
    {
        return FALSE;
    }
    CComBSTR bstrMember(strFunc);
    DISPID dispid = NULL;
    hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,
                                            LOCALE_SYSTEM_DEFAULT,&dispid);
    if(FAILED(hr))
    {
        return FALSE;
    }

    const int arraySize = paramArray.GetSize();

    DISPPARAMS dispparams;
    memset(&dispparams, 0, sizeof dispparams);
    dispparams.cArgs = arraySize;
    dispparams.rgvarg = new VARIANT[dispparams.cArgs];
    
    for( int i = 0; i < arraySize; i++)
    {
        CComBSTR bstr = paramArray.GetAt(arraySize - 1 - i); // back reading
        bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);
        dispparams.rgvarg[i].vt = VT_BSTR;
    }
    dispparams.cNamedArgs = 0;

    EXCEPINFO excepInfo;
    memset(&excepInfo, 0, sizeof excepInfo);
       CComVariant vaResult;
    UINT nArgErr = (UINT)-1;  // initialize to invalid arg
    
    hr = spScript->Invoke(dispid,IID_NULL,0,
                            DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);

    delete [] dispparams.rgvarg;
    if(FAILED(hr))
    {
        return FALSE;
    }
    
    *pVarResult = vaResult;
    return TRUE;
}

实际使用时,可能是先访问(Navigate)了一个页面。然后,在VC里面对这个页面进行一些js调用,并取回结果。有可能这个js调用的函数是这个页面里面没有的。一般可以用eval(一些js语句)这样的形式来调用页面里面没有的函数,但是,现在上面两种方法都不支持eval。

第三种:通过IScriptControl获取当前文档上下文,然后调用IScriptControl::raw_Eval运算。(只能用raw_Eval,用Eval方法会提示没有权限。)
首先定义一个:IScriptControlPtr,然后在OnDocumentComplete里面调用一下 m_spHtmlDoc->get_parentWindow(&m_pHtmlWindow);
IScriptControlPtr->AddObject("window", m_pHtmlWindow, VARIANT_TRUE);

第三种需要import "msscript.ocx"

关闭 返回顶部
联系我们
Copyright © 2011. 聚财吧. All rights reserved.