当前位置 : 主页 > 编程语言 > c++ >

C++和JavaScript脚本的相互调用

来源:互联网 收集:自由互联 发布时间:2021-06-23
脚本调用C++相对比较容易,使用ATL组件只需要抛双接口即可,但在exe里如何做到呢?本文实现了在exe里脚本和C++的相互调用.在EXE里也需要对外抛送一个继承自IDispatch的接口.并需要重载它的
脚本调用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的参数.
网友评论