您的位置:首页 > Web前端 > JavaScript

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

2008-02-18 11:34 417 查看
脚本调用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的参数.



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: