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的参数.
     
     
  • 相关阅读:
    ArcEngine 里面的日期
    ArcEngine连接Oracle数据库
    ArcGIS连接Oracle数据库
    ms sql 带自增列 带外键约束 数据导入导出
    获取指定 MethodInfo 的 MSIL 或者 C# 源码
    架构知识集锦
    ClickOnce手动更新
    委托简单例子
    C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】
    可扩展类库强制取消异步调用
  • 原文地址:https://www.cnblogs.com/blogpro/p/11426776.html
Copyright © 2011-2022 走看看