标签:paramArray 调用 const JavaScript C++ BOOL CComBSTR return NULL
脚本调用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的参数.标签:paramArray,调用,const,JavaScript,C++,BOOL,CComBSTR,return,NULL 来源: https://www.cnblogs.com/blogpro/p/11426776.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。