zoukankan      html  css  js  c++  java
  • C++和JavaScript脚本的相互调用

    脚本调用C++相对比较容易,使用ATL组件只需要抛双接口即可,但在exe里如何做到呢?本文实现了在exe里脚本和C++的相互调用.在EXE里也需要对外抛送一个继承自IDispatch的接口.并需要重载它的所有接口。由于水平有限,所以难免有错。

    // 头文件

    static const GUID IID_CExternal =

    { 0x52fee9af, 0xb3b3, 0x4756, { 0x80, 0x10, 0xfe, 0xa8, 0xf9, 0xfd, 0xd3, 0x3f } };

    class CExternal:public IDispatch

    {

    public:

    CExternal(HWND h);

    virtual ~CExternal();

    ULONG __stdcall AddRef() { return 1; }

    ULONG __stdcall Release() { return 1; }

    HRESULT __stdcall QueryInterface(REFIID riid, void FAR* FAR* ppv)

    {

    if (ppv == NULL)

    return E_POINTER;

    *ppv = NULL;

    if (InlineIsEqualGUID(riid, IID_IUnknown))

    {

    *ppv = static_cast<IUnknown *>(this);

    return S_OK;

    }

    if(InlineIsEqualGUID(riid, IID_IDispatch) )

    {

    *ppv = static_cast<IDispatch FAR *>(this);

    return S_OK;

    }

    if(InlineIsEqualGUID(riid, IID_CExternal) )

    {

    *ppv = static_cast<CExternal *>(this);

    return S_OK;

    }

    return E_NOINTERFACE;

    }

    HRESULT __stdcall GetTypeInfoCount(UINT FAR* pctinfo)

    {

    if (pctinfo == NULL)

    {

    return E_INVALIDARG;

    }

    // there is only one function

    *pctinfo = 1;

    return NOERROR;

    }

    HRESULT __stdcall GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo FAR* FAR* ppTInfo)

    {

    if (ppTInfo == NULL)

    return E_INVALIDARG;

    *ppTInfo = NULL;

    if (iTInfo != 0)

    return DISP_E_BADINDEX;

    *ppTInfo = m_typeinfo;

    if (m_typeinfo!=NULL)

    m_typeinfo->AddRef();

    return NOERROR;

    }

    HRESULT __stdcall GetIDsOfNames(REFIID riid,OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid,DISPID FAR*rgdispid)

    {

    if(lstrcmpiW(*rgszNames,L"exec")==0)

    {

    *rgdispid=0;

    return S_OK;

    }

    return E_FAIL;

    }

    HRESULT __stdcall Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS FAR* pdispparams,VARIANT FAR* pvarResult,EXCEPINFO FAR* pexcepinfo,UINT FAR* puArgErr)

    {

    if((DISPATCH_PROPERTYGET&wFlags || DISPATCH_METHOD&wFlags)

    && dispidMember==0)

    {

    CComBSTR sRet;

    exec(pdispparams, &sRet);

    if (DISPATCH_PROPERTYGET&wFlags)

    {

    pvarResult->vt=VT_BSTR;

    pvarResult->bstrVal=sRet.Detach();

    }

    return S_OK;

    }

    return E_FAIL;

    }

    HRESULT __stdcall exec(DISPPARAMS FAR* pdispparams, BSTR *pbstrValue);

    private:

    HWND m_hWnd;

    LPTYPEINFO m_typeinfo;

    CString GetVariantStr(VARIANT vVal);

    };

    // 实现的文件

    CExternal::CExternal(HWND h)

    {

    csDisplayStr = "";

    m_typeinfo =NULL;

    m_hWnd = h;

    // Create an exec function

    static PARAMDATA PARAM_VALUE[]={{OLESTR("fnName"),VT_BSTR},{OLESTR("p1"),VT_BSTR}};

    static METHODDATA rgmdataCCalc={OLESTR("exec"),PARAM_VALUE,0,0,CC_CDECL,2,DISPATCH_METHOD|DISPATCH_PROPERTYGET,VT_BSTR};

    static INTERFACEDATA ifdata={&rgmdataCCalc, 1};

    HRESULT hres=CreateDispTypeInfo(&ifdata, LOCALE_SYSTEM_DEFAULT, &m_typeinfo);

    }

    CString CExternal::GetVariantStr(VARIANT vVal)

    {

    CString csReVal;

    switch (vVal.vt)

    {

    case VT_BOOL:

    {

    if (vVal.boolVal == VARIANT_TRUE)

    {

    return("1");

    }

    else

    {

    return("0");

    }

    break;

    }

    case VT_I2:

    {

    csReVal.Format("%d",vVal.iVal);

    return(csReVal);

    }

    case VT_I4:

    {

    csReVal.Format("%d",vVal.lVal);

    return(csReVal);

    }

    // case VT_R8:

    // {

    // //csReVal.Format("%f",vVal.dblVal);

    // csReVal=vVal.dblVal;

    // return(csReVal);

    // }

    case VT_BSTR:

    {

    return(CString(vVal.bstrVal));

    }

    }

    return "";

    }

    HRESULT __stdcall CExternal::exec(DISPPARAMS FAR* pdispparams, BSTR *pbstrValue) // 脚本的入口点

    {

    // no argument return

    if (pdispparams->cArgs < 1)

    {

    *pbstrValue = bstrRet.Detach();

    return S_OK;

    }

    int args = pdispparams->cArgs;

    // C calling convention order of parameters is in reversed

    CString action = pdispparams->rgvarg[args-1].bstrVal;

    debugIt(" exec***action:%s:%d ",action,args);

    if (action == "alert")

    {

    CString csMessage;

    CString csTitle;

    if (args > 1)

    {

    csMessage= GetVariantStr(pdispparams->rgvarg[args-2]);

    }

    if (args > 2)

    {

    csTitle = GetVariantStr(pdispparams->rgvarg[args-3]);

    }

    MessageBox(m_hWnd, LPCSTR(csMessage), LPCSTR(csTitle), MB_OK);

    }

    //else if(action == "什么")

    //{

    //}

    *pbstrValue=bstrRet.Detach(); // 返回值

    return S_OK;

    }

    CExternal::~CExternal()

    {

    if(m_typeinfo) m_typeinfo->Release();

    }

    C++调用脚本可以使用下面的代码,此代码是我在网上下载的,具体的来源我已经不记得了,但在网上应该可以找到类似的.原理是用到了WebBrowser2,但是C++和脚本的相互调用都用到了HTML页面,使用HTML页面成了包袱,能否丢掉它,我不知道如何实现,望高手指点.......

    // 头文件

    #pragma once

    #include <atlbase.h>

    #include <Mshtml.h>

    class CCallScript

    {

    public:

    CCallScript();

    virtual ~CCallScript();

    BOOL DocumentSet(){return(m_bDocumentSet);}

    BOOL SetDocument(IDispatch* pDisp);

    LPDISPATCH GetHtmlDocument() const;

    const CComBSTR GetLastError() const;

    BOOL GetScript(CComPtr<IDispatch>& spDisp);

    BOOL GetScripts(CComPtr<IHTMLElementCollection>& spColl);

    BOOL Run(const CComBSTR strFunc,CComVariant* pVarResult = NULL);

    BOOL Run(const CComBSTR strFunc,const CComBSTR strArg1,CComVariant* pVarResult = NULL);

    BOOL Run(const CComBSTR strFunc,const CComBSTR strArg1,const CComBSTR strArg2,CComVariant* pVarResult = NULL);

    BOOL Run(const CComBSTR strFunc,const CComBSTR strArg1,const CComBSTR strArg2,const CComBSTR strArg3,CComVariant* pVarResult = NULL);

    BOOL Run(const CComBSTR strFunc,const CSimpleArray<CComBSTR> & paramArray,CComVariant* pVarResult = NULL);

    private:

    BOOL m_bDocumentSet;

    protected:

    void ShowError(CComBSTR lpszText);

    protected:

    CComPtr<IHTMLDocument2> m_spDoc;

    CComBSTR m_strError;

    };

    inline void CCallScript::ShowError(CComBSTR lpszText)

    {

    m_strError = "Error: ";

    m_strError.Append(lpszText);

    }

    inline const CComBSTR CCallScript::GetLastError() const

    {

    return m_strError;

    }

    inline LPDISPATCH CCallScript::GetHtmlDocument() const

    {

    return m_spDoc;

    }

    // CPP文件

    #include "stdafx.h"

    #include "CallScript.h"

    #define CHECK_POINTER(p)

    ATLASSERT(p != NULL);

    if(p == NULL)

    {

    ShowError("NULL pointer");

    return FALSE;

    }

    const CComBSTR GetSystemErrorMessage(DWORD dwError)

    {

    CComBSTR strError;

    LPTSTR lpBuffer;

    if(!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

    NULL, dwError,

    MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),

    (LPTSTR) &lpBuffer, 0, NULL))

    {

    strError = "FormatMessage Netive Error" ;

    }

    else

    {

    strError = lpBuffer;

    LocalFree(lpBuffer);

    }

    return strError;

    }

    CCallScript::CCallScript()

    {

    m_bDocumentSet = FALSE;

    }

    CCallScript::~CCallScript()

    {

    }

    BOOL CCallScript::SetDocument(IDispatch* pDisp)

    {

    CHECK_POINTER(pDisp);

    m_spDoc = NULL;

    CComPtr<IDispatch> spDisp = pDisp;

    HRESULT hr = spDisp->QueryInterface(IID_IHTMLDocument2,(void**)&m_spDoc);

    if(FAILED(hr))

    {

    ShowError("Failed to get HTML document COM object");

    return FALSE;

    }

    m_bDocumentSet = TRUE;

    return TRUE;

    }

    BOOL CCallScript::GetScript(CComPtr<IDispatch>& spDisp)

    {

    CHECK_POINTER(m_spDoc);

    HRESULT hr = m_spDoc->get_Script(&spDisp);

    ATLASSERT(SUCCEEDED(hr));

    return SUCCEEDED(hr);

    }

    BOOL CCallScript::GetScripts(CComPtr<IHTMLElementCollection>& spColl)

    {

    CHECK_POINTER(m_spDoc);

    HRESULT hr = m_spDoc->get_scripts(&spColl);

    ATLASSERT(SUCCEEDED(hr));

    return SUCCEEDED(hr);

    }

    BOOL CCallScript::Run(const CComBSTR strFunc,CComVariant* pVarResult)

    {

    CSimpleArray<CComBSTR> paramArray;

    return Run(strFunc,paramArray,pVarResult);

    }

    BOOL CCallScript::Run(const CComBSTR strFunc,const CComBSTR strArg1,CComVariant* pVarResult)

    {

    CSimpleArray<CComBSTR> paramArray;

    paramArray.Add((CComBSTR &)strArg1);

    return Run(strFunc,paramArray,pVarResult);

    }

    BOOL CCallScript::Run(const CComBSTR strFunc,const CComBSTR strArg1,const CComBSTR strArg2,CComVariant* pVarResult)

    {

    CSimpleArray<CComBSTR> paramArray;

    paramArray.Add((CComBSTR &)strArg1);

    paramArray.Add((CComBSTR &)strArg2);

    return Run(strFunc,paramArray,pVarResult);

    }

    BOOL CCallScript::Run(const CComBSTR strFunc,const CComBSTR strArg1,const CComBSTR strArg2,const CComBSTR strArg3,CComVariant* pVarResult)

    {

    CSimpleArray<CComBSTR> paramArray;

    paramArray.Add((CComBSTR &)strArg1);

    paramArray.Add((CComBSTR &)strArg2);

    paramArray.Add((CComBSTR &)strArg3);

    return Run(strFunc,paramArray,pVarResult);

    }

    BOOL CCallScript::Run(const CComBSTR strFunc, const CSimpleArray<CComBSTR>& paramArray,CComVariant* pVarResult)

    {

    CComPtr<IDispatch> spScript;

    if(!GetScript(spScript))

    {

    ShowError("Cannot GetScript");

    return FALSE;

    }

    CComBSTR bstrMember(strFunc);

    DISPID dispid = NULL;

    HRESULT hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,

    LOCALE_SYSTEM_DEFAULT,&dispid);

    if(FAILED(hr))

    {

    ShowError(GetSystemErrorMessage(hr));

    return FALSE;

    }

    //const int arraySize = paramArray.GetCount();

    const int arraySize = paramArray.GetSize();

    DISPPARAMS dispparams;

    memset(&dispparams, 0, sizeof dispparams);

    dispparams.cArgs = arraySize;

    dispparams.rgvarg = new VARIANT[dispparams.cArgs];

    //__asm {int 3}

    CComBSTR bstr;

    for( int i = 0; i < arraySize; i++)

    {

    bstr.Empty();

    //CComBSTR bstr = paramArray.GetAt(arraySize - 1 - i); // back reading

    bstr = paramArray[arraySize - 1 - i]; // back reading

    //bstr.CopyTo(&dispparams.rgvarg[i].bstrVal); //memory leak

    dispparams.rgvarg[i].bstrVal = bstr.m_str; //also cause problem when paras are more than 1

    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);

    /////////////// bug fix memory leak code start ///////////////

    // for( int j = 0; j < arraySize; j++)

    // ::SysFreeString(dispparams.rgvarg[j].bstrVal);

    /////////////// bug fix memory leak code end ///////////////

    delete [] dispparams.rgvarg;

    if(FAILED(hr))

    {

    ShowError(GetSystemErrorMessage(hr));

    return FALSE;

    }

    if(pVarResult)

    {

    *pVarResult = vaResult;

    }

    return FALSE;

    }

    这两个文件的使用的方法:

    // Get the browser control.

    CAxWindow wnd = GetDlgItem(IDC_EXPLORER); // WebBrowser

    wnd.QueryControl( &m_spBrowser );

    CComPtr<IAxWinAmbientDispatch> spAmbient;

    HRESULT hr = wnd.QueryHost(&spAmbient);

    // diable the context menu

    // disable the scrollbar

    if( SUCCEEDED(hr) )

    {

    spAmbient->put_AllowContextMenu(VARIANT_TRUE);

    spAmbient->put_DocHostFlags(docHostUIFlagFLAT_SCROLLBAR);

    }

    // navigate to the base html

    VARIANT flag = {0};

    VARIANT name = {0};

    VARIANT post = {0};

    VARIANT head = {0};

    //

    // m_spBrowser->Navigate(_bstr_t(GetFullName("WhizConsoleSlave.html")), &flag, &name, &post, &head);

    TCHAR szFileName[MAX_PATH];

    ::GetModuleFileName(_Module.GetModuleInstance(), szFileName, MAX_PATH);

    TCHAR szRes[MAX_PATH+10];

    ::wsprintf(szRes, _T("res://%s/%0d"), szFileName, IDR_HTML);

    CComVariant vURL(szRes);

    m_spBrowser->Navigate2(&vURL, &flag, &name, &post, &head); // 显示指定的页面

    // Create a wrapper about the external dispatch interface

    CComObject<CWrapperDispatch>* spdispWrapper = 0;

    hr = CComObject<CWrapperDispatch>::CreateInstance(&spdispWrapper);

    if( FAILED(hr) ) return 0;

    // Dummy for refcount management

    CComPtr<IUnknown> spUnk = spdispWrapper;

    // Create the object that will handle the external interface for the

    // html file.

    pExternal = new CExternal(m_hWnd);

    m_oExternal = static_cast<IDispatch *>(pExternal);

    // Set the external dispatch interface

    spdispWrapper->SetDispatch(m_oExternal); // 对脚本抛送接口

    hr = wnd.SetExternalDispatch(spdispWrapper);

    // wnd.SetFocus();

    // ******************************************************************

    // 调用脚本比较容易

    if ( m_CallScript.DocumentSet() == FALSE)

    {

    IDispatch* d = NULL;

    m_spBrowser->get_Document(&d);

    m_CallScript.SetDocument(d);

    d->Release();

    }

    m_CallScript.Run(L"DisplayStr"); // DisplayStr就是脚本的函数

    m_CallScript.Run(L"AddDir","a","b"); // AddDir也是脚本的函数,a和b是AddDir的参数.

  • 相关阅读:
    python-IO编程
    DNS解析流程
    python-模块
    HTTP协议
    python-函数式编程
    nmap扫描结果的6种端口状态
    python-高级特性
    python-函数
    python-基础
    上传之路
  • 原文地址:https://www.cnblogs.com/blogpro/p/11446063.html
Copyright © 2011-2022 走看看