脚本调用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的参数.

C++和JavaScript脚本的相互调用的更多相关文章

  1. ASP.net关于C#代码与javaScript函数的相互调用

    C#代码与javaScript函数的相互调用 问:1.如何在JavaScript访问C#函数?2.如何在JavaScript访问C#变量?3.如何在C#中访问JavaScript的已有变量?4.如何在 ...

  2. JavaScript 父子页面相互调用总结

    父子页面相互调用是一个在开发中经常遇到的问题,但是没有找到过比较全面的文章介绍.在此总结下来,供大家参考. 四种方式 一般情况下,我们可以使用iframe.window的open.showModalD ...

  3. Javascript与C#相互调用

    javascript调用C#代码 前台js调用后台代码方法,此方法只适用于后台方法的修饰符为public或protected,如果是其他修饰符会报错. >后台C#代码: protected in ...

  4. shell脚本里面相互调用时路径不要用pwd获取

    shellA调用shellB,如果shellB 里面需要使用路径作为变量,去寻找其它文件.那么要注意,不用pwd,其返回的是系统中用户当前所在位置的路径,也就是shellA的路径,这样就错了.应该用d ...

  5. WebView和JavaScript如何实现相互调用

    WebView可以同JavaScript互相调用,因此我们可以用HTML和JavaScript来辅助编写Android应用. 示例:使用javaScript获取Android程序中的对象数据 clas ...

  6. C#代码和javascript函数相互调用

    C#代码与javaScript函数的相互调用 问:1.如何在JavaScript访问C#函数?2.如何在JavaScript访问C#变量?3.如何在C#中访问JavaScript的已有变量?4.如何在 ...

  7. android与javascript相互调用

    下面这一节来介绍android和javascript是怎么相互调用的,这样我们的UI界面设计起来就简单多了,而且UI设计起来也可以跨平台.现在有好多web app前台框架了,比如sencha和jque ...

  8. MySql创建函数与过程,触发器, shell脚本与sql的相互调用。

    一:函数 1:创建数据库和表deptartment, mysql> use DBSC; Database changed mysql), ), )); Query OK, rows affect ...

  9. JavaScript脚本在页面中放置的位置

    JavaScript脚本通常放置在三个位置: 1.head部分JavaScript脚本. 2.body部分JavaScript脚本. 3.单独以.js结尾的文件中的JavaScript脚本. 客户端会 ...

随机推荐

  1. CKEditor与CKFinder学习--自定义界面及按钮事件捕获

    原文地址:CKEditor与CKFinder学习--自定义界面及按钮事件捕获  讨厌CSDN的广告,吃香太难看! 效果图 界面操作图 原始界面 调整后的界面(删除了flush,表单元素等) 该界面的皮 ...

  2. ADS 命令行命令介绍

    armasm 1. 命令:armasm [选项] -o 目标文件 源文件 2. 选项说明 -Errors 错误文件名        ;指定一个错误输出文件 -I 目录[,目录]          ;指 ...

  3. 带你彻底理解RSA算法原理,很简单的

    1. 什么是RSA RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法. 在了解RSA算法之前,先熟悉下几个术语 根据密钥的使用方法,可以将密码分为 对称密码 和 公钥密码 对称 ...

  4. scala自定义隐式转换

    Scala自定义隐式转换 一.编写隐式转换类 /** * Author Mr. Guo * Create 2019/4/20 - 17:40 */ object StringImprovments { ...

  5. laravel 关掉debug

    修改.env文件 APP_DEBUG=false 然后把Laravel服务重启一下

  6. 16. 继承(extends)

    1.语法 class 类名1 extends 类名2{ //成员变量和成员方法 } 2.继承要注意的事项: 1)千万不要为了减少重复代码而去继承,只有真正存在着继承关系的时候才去继承. 2)父类私有的 ...

  7. 【JZOJ6411】上网

    description analysis 如果把所有大小关系连成边,小的往大的连,就可以直接上拓扑 暴力连边时间复杂度\(O(n^2)\),然而连边的过程,考虑用线段树优化 线段树上的所有儿子节点向父 ...

  8. 使用CGIHTTPServer搭建简单网站

    目录 一.前提准备 二.搭建web网站 如何快速搭建web网站?这个问题对于我这样的小白来说简直就是一脸懵逼毫无头绪.在学习python的过程接触到了 CGI 编程,至于CGI是什么?怎么运行的?这我 ...

  9. MySQL主键跟外键

    定义主键和外键主要是为了维护关系数据库的完整性,总结一下: 1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄. 身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证 ...

  10. Java中的并发库学习总结

    我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量Java ...