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

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

//  头文件
static   const  GUID IID_CExternal  =
0x52fee9af0xb3b30x47560x800x100xfe0xa80xf90xfd0xd30x3f } } ;


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, 0sizeof dispparams);
    dispparams.cArgs 
= arraySize;
    dispparams.rgvarg 
= new VARIANT[dispparams.cArgs];
    
//__asm {int 3}
    CComBSTR bstr;
    
forint 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, 0sizeof 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的参数.

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值