<script type="text/javascript">
</script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
<转载时请注明出处--Waiting4you>
在优快云上看到有不少人问怎样才能象MS Office一样支持VBA,偶也很感兴趣,可惜Google后发现要支持VBA得付钱给M$才行,象我们这种无产阶级自然是只有想的份啦。
不过MS还是有点“爱心”D,它给了我们另外一个选择——ActiveX Scripting(后面简称[AS])。
简单的说[AS]就是:MS来帮我们解析脚本里的基本语句(如if、for、表态式、赋值等),我们负责解释、执行它所不认识的函数,对象。
下面再简单说一下操作[AS]的流程:
1. 实例化一个脚本对象(IActiveScript),一般装了IE的电脑上应该都有JScript和VBScript。
2. 告诉IActiveScript谁来解释脚本中的对象(IActiveScript ::SetScriptSite)
3. 告诉IActiveScript脚本里会用到哪些对象(用IActiveScript ::AddNamedItem)
4. 装入脚本(JScript或VBScript代码,UNICODE格式)
5. 运行脚本(通过设置IActiveScript ::SetScriptState实现)
6. [AS]在运行脚本过程中如果遇到第3步里告诉它的对象,它就会向我们要此对象的接口以便继续执行(它会调用IActiveScriptSite::GetItemInfo,第2步里告诉它的)。
7. 打完收工。当然也可以强制停下运行中的脚本(比如不小心编了一个死循环的脚本)。也是通过设置IActiveScript ::SetScriptState实现。
从上面可以看出,我们的主要工作是实现脚本里的对象的解释工作。在COM编程中,毫无悬念地,这个光荣而又艰巨的任务就又落到了IDispatch身上。IDispatch的生平事迹咱就不介绍了,不明白的去问明白的,都不明白的去Google,心急的可以看后面的示例代码。
对我们编程的来说,说再多也不如源代码来得直接有效,下面我们就来做一个支持脚本的小程序。这里我们使用BCB来做,其它如VC,GCC当然也行,不过对于快速原型开发方面,BCB绝对是不二选择(广告时间)。
先看偶写的一个JScript脚本:
var
bForward
=
true
;
for
(
var
i
=
0
;i
<
ScreenWidth
-
200
;i
+=
100
)

...
{
for(var j=0;j<ScreenHeight-200;j+=10)

...{
var x = i;
var y = bForward? j : (ScreenHeight-200-j)
MyWin.MoveTo(x,y);
MyWin.Caption = "X:" + x + " Y:"+y;
MyWin.Color = (x<<16|y)&0xffffff;
Sleep(10);
}
bForward = !bForward;
}
此脚本的目的是让一个叫MyWin的窗口从左到右地上下移动,同时改变标题和颜色。
前面说了MS只帮我们解决脚本语言上的问题,我们来处理对象和函数。在这个脚本里,我们的任务有:ScreenWidth、ScreenHeight、Sleep、MyWin对象以及它的方法属性。
这里还得说一下IDispatch的调用过程:比如当[AS]执行到MyWin.MoveTo(x,y);时,它先得到MyWin的IDispatch接口(它是怎么得到的?后面会讲先按下不提),然后调用IDispatch的GetIDsOfNames(riid,L"MoveTo",1,lcid,&rgDispId)获得MoveTo对应的"Member Id"(rgDispId参数)。再用这个"Member Id"去调用Invoke(rgDispId,...)。所以我们只需关注GetIDsOfNames和Invoke两个方法即可。
先编写一个TMyGlobalFunc来处理ScreenWidth、ScreenHeight、Sleep这三个全局函数:
struct
TMyGlobalFunc : TDispatch
...
{

enum ...{itemScreenWidth,itemScreenHeight,itemSleep};
static wchar_t Name[];
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,

DISPID *rgDispId)...{

if(lstrcmpW(rgszNames[0],L"ScreenWidth") == 0)...{
*rgDispId = itemScreenWidth;
}

else if(lstrcmpW(rgszNames[0],L"ScreenHeight") == 0) ...{
*rgDispId = itemScreenHeight;
}

else if(lstrcmpW(rgszNames[0],L"Sleep") == 0) ...{
*rgDispId = itemSleep;
}
else
return E_NOTIMPL;
return S_OK;
}

STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,

VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)...{
switch(dispIdMember)

...{
case itemScreenWidth:
pVarResult->vt=VT_I4;
pVarResult->intVal = Screen->Width;
break;
case itemScreenHeight:
pVarResult->vt=VT_I4;
pVarResult->intVal = Screen->Height;
break;
case itemSleep:
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
Application->ProcessMessages();
Sleep(pDispParams->rgvarg[0].intVal);
break;
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}
}
;
wchar_t TMyGlobalFunc::Name[]
=
L
"
MyGlobalFunc
"
;

再写个TMyWin来处理MyWin对象的方法和属性,和上面一样
struct
TMyWin : TDispatch
...
{

enum ...{itemCaption,itemColor,itemMoveTo};
static wchar_t Name[];
// IDispatch
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,

DISPID *rgDispId)...{

if(lstrcmpW(rgszNames[0],L"Caption") == 0) ...{
*rgDispId = itemCaption;
}

else if(lstrcmpW(rgszNames[0],L"Color") == 0) ...{
*rgDispId = itemColor;
}

else if(lstrcmpW(rgszNames[0],L"MoveTo") == 0) ...{
*rgDispId = itemMoveTo;
}
else
return E_NOTIMPL;
return S_OK;
}

STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,

VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)...{
switch(dispIdMember)

...{
case itemCaption:

...{
if(wFlags==DISPATCH_PROPERTYGET)

...{
pVarResult->vt = VT_BSTR;
pVarResult->bstrVal = GetCaption();
}
else if(wFlags==DISPATCH_PROPERTYPUT)

...{
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_BSTR) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
SetCaption(pDispParams->rgvarg[0].bstrVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
case itemColor:

...{
if(wFlags==DISPATCH_PROPERTYGET)

...{
pVarResult->vt = VT_I4;
pVarResult->intVal = GetColor();
}
else if(wFlags==DISPATCH_PROPERTYPUT)

...{
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
SetColor(pDispParams->rgvarg[0].intVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
case itemMoveTo:

...{
if(wFlags==DISPATCH_METHOD)

...{
if(pDispParams->cArgs!=2) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}

else if(pDispParams->rgvarg[1].vt != VT_I4)...{
*puArgErr = 1;
return DISP_E_TYPEMISMATCH;
}
MoveTo( pDispParams->rgvarg[1].intVal,
pDispParams->rgvarg[0].intVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}

// TMyWin上所有的方法属性都对这个TForm *fm_Opt操作

TMyWin(TForm *fm_Opt) : TDispatch(),m_Form(fm_Opt)...{ ; }


BSTR GetCaption()...{
return WideString(m_Form->Caption).Detach();
}

void SetCaption(BSTR bstrCaption)...{
m_Form->Caption = bstrCaption;
}

int GetColor()...{
return (int)m_Form->Color;
}

void SetColor(int iColor)...{
m_Form->Color = TColor(iColor);
}


void MoveTo(int X,int Y)...{
m_Form->Left=X;
m_Form->Top=Y;
}

private:
TForm *m_Form;
}
;
wchar_t TMyWin::Name[]
=
L
"
MyWin
"
;
主要任务完成,接着我们要实现IActiveScriptSite,它用于上面所说的第2步和第6步。[AS]解析上面的脚本时遇到MyWin及ScreenWidth、ScreenHeight、Sleep时会通过GetItemInfo向它要接口,它则负责把我们刚才写的IDispatch喂给[AS]。
这个IActiveScriptSite要包含头文件#include <activscp.h>
struct
TMyActiveScriptSite
: IActiveScriptSite

...
{
TMyActiveScriptSite(TMyWin *pMyWin,TMyGlobalFunc *pMyGlobalFunc)

: m_iRefCount(1),m_pMyWin(pMyWin),m_pMyGlobalFunc(pMyGlobalFunc)...{
}

// IUNKnown,不得不写

HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)...{
if(iid==IID_IUnknown||iid==IID_IActiveScriptSite)

...{
*ppv=this;
AddRef();
return S_OK;
}
*ppv=NULL;
return E_NOINTERFACE;
}

ULONG __stdcall AddRef(void) ...{
return ++m_iRefCount;
}

ULONG __stdcall Release(void) ...{

if(--m_iRefCount==0)...{
delete this;
return 0;
}
return m_iRefCount;
}

// IActiveScriptSite

STDMETHOD(GetLCID)(LCID* /**//*plcid*/) ...{
return E_NOTIMPL;
}
//主要的就是这个
STDMETHOD(GetItemInfo)(LPCOLESTR pstrName,
DWORD dwReturnMask,
IUnknown** ppiunkItem,

ITypeInfo** ppti) ...{

if( (dwReturnMask & SCRIPTINFO_ITYPEINFO)!=0 )...{
*ppti = NULL;
return E_FAIL;
}
if( (dwReturnMask & SCRIPTINFO_IUNKNOWN)==0 ) return E_FAIL;
if( ppiunkItem==NULL ) return E_POINTER;
*ppiunkItem = NULL;

if( lstrcmpW( pstrName, TMyWin::Name )==0 ) ...{ //[AS]要MyWin,送上!
m_pMyWin->AddRef();
*ppiunkItem = m_pMyWin;
return S_OK;
}

else if( lstrcmpW( pstrName, TMyGlobalFunc::Name )==0 ) ...{ //[AS]要MyGlobalFunc,送上!
m_pMyGlobalFunc->AddRef();
*ppiunkItem = m_pMyGlobalFunc;
return S_OK;
}
return E_FAIL; //要其它的,没有!
}


STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) ...{
if( pbstrVersion==NULL ) return E_POINTER;
*pbstrVersion = ::SysAllocString(OLESTR("Script 1.0"));
return S_OK;
}

STDMETHOD(OnScriptTerminate)(

const VARIANT* /**//*pvarResult*/,

const EXCEPINFO* /**//*pexcepinfo*/) ...{
return S_OK;
}


STDMETHOD(OnStateChange)(SCRIPTSTATE /**//*ssScriptState*/) ...{
return S_OK;
}
// 脚本里有错误时会调用OnScriptError

STDMETHOD(OnScriptError)(IActiveScriptError* pScriptError) ...{
EXCEPINFO e;
DWORD dwContext;
ULONG ulLine;
LONG lPos;
pScriptError->GetExceptionInfo(&e);
pScriptError->GetSourcePosition(&dwContext, &ulLine, &lPos);
char *pstrFormat = "An error occured while parsing script: Source: %ws Error: %08X Description: %ws Line: %d";
char pstrStr[1024];
::wsprintf( pstrStr, pstrFormat,
e.bstrSource,
e.scode,
e.bstrDescription,
ulLine+1);
::MessageBox(::GetActiveWindow(), pstrStr, _T("Compile Error"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
return S_OK;
}


STDMETHOD(OnEnterScript)() ...{
return S_OK;
}


STDMETHOD(OnLeaveScript)() ...{
return S_OK;
}
private:
TMyWin *m_pMyWin;
TMyGlobalFunc *m_pMyGlobalFunc;
int m_iRefCount;
}
;
万事俱备,就等执行了:
打开BCB,新建一VCL Form Application。
在默认的Form1上加入一个TMemo改名为:mmoScript;加入一个TButton改名为btnRun。btnRun->OnClick代码:
偷懒用到了TComInterface,要包含: #include <utilcls.h>
void
__fastcall TForm1::btnRunClick(TObject
*
Sender)

...
{
TComInterface<IActiveScript> pAS;
pAS.CreateInstance(L"JScript"); // 第一步,实例化Jscript(同学们也可以试试VBScript)
if(!pAS) return;

TComInterface<IActiveScriptParse> pASP(pAS);
if(!pASP) return;

pASP->InitNew();

// 我们的劳动成果在这里
TComInterface<TMyWin> pDispatch_MyWin = new TMyWin(this);
TComInterface<TMyGlobalFunc> pDispatch_MyGlobalFunc = new TMyGlobalFunc;
TComInterface<TMyActiveScriptSite> pActiveScriptSite_Mine = new TMyActiveScriptSite(pDispatch_MyWin,pDispatch_MyGlobalFunc);
//第二步,告诉IActiveScript谁来解释脚本中的对象
pAS->SetScriptSite(pActiveScriptSite_Mine);
//第三步,告诉IActiveScript脚本里会用到哪些对象
pAS->AddNamedItem(TMyWin::Name,SCRIPTITEM_ISVISIBLE); //会用到”MyWin”
pAS->AddNamedItem(TMyGlobalFunc::Name,SCRIPTITEM_ISVISIBLE|SCRIPTITEM_GLOBALMEMBERS); //多了一个SCRIPTITEM_GLOBALMEMBERS,意思是如果遇到全局函数就向”MyGlobalFunc”要。
//第四步,装入脚本
pASP->ParseScriptText(WideString(mmoScript->Lines->Text),
NULL,
NULL,
NULL,
0,
0,
0,
NULL,
NULL);

//第五步,运行脚本
pAS->SetScriptState(SCRIPTSTATE_STARTED);
pAS->Close();
}
编译,运行。
把写的Jscript代码拷贝到mmoScript里然后按btnRun运行可以看到效果。当然也可以修改脚本弄点更好玩的花样出来,呵呵。
最后还要多说一句关于ParseScriptText,用好它后面的几个参数。看MSDN,修改其中一个参数这段代码就可以用作表态式解析了。
附上完整代码:
Script.h
#ifndef SCRIPT_H
#define
SCRIPT_H
//
=============================================================
#include
<
tchar.h
>
#include
<
activscp.h
>

//
TDispatch:简单实现IDispath的所有方法,用于作自动化对象的基类。

struct
TDispatch : IDispatch
...
{

TDispatch():m_iRefCount(1)...{;}

~TDispatch()...{;}
// IUNKnown

HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)...{
if(iid==IID_IUnknown||iid==IID_IDispatch)

...{
*ppv=this;
AddRef();
return S_OK;
}
*ppv=NULL;
return E_NOINTERFACE;
}

ULONG __stdcall AddRef(void) ...{
return ++m_iRefCount;
}

ULONG __stdcall Release(void) ...{

if(--m_iRefCount==0)...{
delete this;
return 0;
}
return m_iRefCount;
}

// IDispatch

STDMETHOD(GetTypeInfoCount)(UINT *pctinfo)...{return S_OK;}

STDMETHOD(GetTypeInfo)(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo)...{return S_OK;}
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,

DISPID *rgDispId)...{
return E_NOTIMPL;
}

STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,

VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)...{
return S_OK;
}
private:
int m_iRefCount;
}
;

//
TMyWin,实现MyWin对象类,解释Caption,Color属性,MoveTo方法

struct
TMyWin : TDispatch
...
{

enum ...{itemCaption,itemColor,itemMoveTo};
static wchar_t Name[];
// IDispatch
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,

DISPID *rgDispId)...{
if(lstrcmpW(rgszNames[0],L"Caption") == 0)

...{
*rgDispId = itemCaption;
}
else if(lstrcmpW(rgszNames[0],L"Color") == 0)

...{
*rgDispId = itemColor;
}
else if(lstrcmpW(rgszNames[0],L"MoveTo") == 0)

...{
*rgDispId = itemMoveTo;
}
else
return E_NOTIMPL;
return S_OK;
}

STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,

VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)...{
switch(dispIdMember)

...{
case itemCaption:

...{
if(wFlags==DISPATCH_PROPERTYGET)

...{
pVarResult->vt = VT_BSTR;
pVarResult->bstrVal = GetCaption();
}
else if(wFlags==DISPATCH_PROPERTYPUT)

...{
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_BSTR) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
SetCaption(pDispParams->rgvarg[0].bstrVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
case itemColor:

...{
if(wFlags==DISPATCH_PROPERTYGET)

...{
pVarResult->vt = VT_I4;
pVarResult->intVal = GetColor();
}
else if(wFlags==DISPATCH_PROPERTYPUT)

...{
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
SetColor(pDispParams->rgvarg[0].intVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
case itemMoveTo:

...{
if(wFlags==DISPATCH_METHOD)

...{
if(pDispParams->cArgs!=2) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}

else if(pDispParams->rgvarg[1].vt != VT_I4)...{
*puArgErr = 1;
return DISP_E_TYPEMISMATCH;
}
MoveTo( pDispParams->rgvarg[1].intVal,
pDispParams->rgvarg[0].intVal);
}
else
return DISP_E_MEMBERNOTFOUND;
break;
}
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}

// TMyWin

TMyWin(TForm *fm_Opt) : TDispatch(),m_Form(fm_Opt)...{ ; }


BSTR GetCaption()...{
return WideString(m_Form->Caption).Detach();
}

void SetCaption(BSTR bstrCaption)...{
m_Form->Caption = bstrCaption;
}

int GetColor()...{
return (int)m_Form->Color;
}

void SetColor(int iColor)...{
m_Form->Color = TColor(iColor);
}


void MoveTo(int X,int Y)...{
m_Form->Left=X;
m_Form->Top=Y;
}

private:
TForm *m_Form;
}
;
wchar_t TMyWin::Name[]
=
L
"
MyWin
"
;


struct
TMyGlobalFunc : TDispatch
...
{

enum ...{itemScreenWidth,itemScreenHeight,itemSleep};
static wchar_t Name[];
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,

DISPID *rgDispId)...{
if(lstrcmpW(rgszNames[0],L"ScreenWidth") == 0)

...{
*rgDispId = itemScreenWidth;
}
else if(lstrcmpW(rgszNames[0],L"ScreenHeight") == 0)

...{
*rgDispId = itemScreenHeight;
}
else if(lstrcmpW(rgszNames[0],L"Sleep") == 0)

...{
*rgDispId = itemSleep;
}
else
return E_NOTIMPL;
return S_OK;
}

STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
DISPPARAMS *pDispParams,

VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)...{
switch(dispIdMember)

...{
case itemScreenWidth:
pVarResult->vt=VT_I4;
pVarResult->intVal = Screen->Width;
break;
case itemScreenHeight:
pVarResult->vt=VT_I4;
pVarResult->intVal = Screen->Height;
break;
case itemSleep:
if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;

if(pDispParams->rgvarg[0].vt != VT_I4) ...{
*puArgErr = 0;
return DISP_E_TYPEMISMATCH;
}
Application->ProcessMessages();
Sleep(pDispParams->rgvarg[0].intVal);
break;
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}
}
;
wchar_t TMyGlobalFunc::Name[]
=
L
"
MyGlobalFunc
"
;

struct
TMyActiveScriptSite
: IActiveScriptSite

...
{
TMyActiveScriptSite(TMyWin *pMyWin,TMyGlobalFunc *pMyGlobalFunc)

: m_iRefCount(1),m_pMyWin(pMyWin),m_pMyGlobalFunc(pMyGlobalFunc)...{
}

// IUNKnown

HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)...{
if(iid==IID_IUnknown||iid==IID_IActiveScriptSite)

...{
*ppv=this;
AddRef();
return S_OK;
}
*ppv=NULL;
return E_NOINTERFACE;
}

ULONG __stdcall AddRef(void) ...{
return ++m_iRefCount;
}

ULONG __stdcall Release(void) ...{

if(--m_iRefCount==0)...{
delete this;
return 0;
}
return m_iRefCount;
}

// IActiveScriptSite

STDMETHOD(GetLCID)(LCID* /**//*plcid*/) ...{
return E_NOTIMPL;
}

STDMETHOD(GetItemInfo)(LPCOLESTR pstrName,
DWORD dwReturnMask,
IUnknown** ppiunkItem,

ITypeInfo** ppti) ...{

if( (dwReturnMask & SCRIPTINFO_ITYPEINFO)!=0 )...{
*ppti = NULL;
return E_FAIL;
}
if( (dwReturnMask & SCRIPTINFO_IUNKNOWN)==0 ) return E_FAIL;
if( ppiunkItem==NULL ) return E_POINTER;
*ppiunkItem = NULL;

if( lstrcmpW( pstrName, TMyWin::Name )==0 ) ...{
m_pMyWin->AddRef();
*ppiunkItem = m_pMyWin;
return S_OK;
}

else if( lstrcmpW( pstrName, TMyGlobalFunc::Name )==0 ) ...{
m_pMyGlobalFunc->AddRef();
*ppiunkItem = m_pMyGlobalFunc;
return S_OK;
}
return E_FAIL;
}


STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) ...{
if( pbstrVersion==NULL ) return E_POINTER;
*pbstrVersion = ::SysAllocString(OLESTR("Script 1.0"));
return S_OK;
}

STDMETHOD(OnScriptTerminate)(

const VARIANT* /**//*pvarResult*/,

const EXCEPINFO* /**//*pexcepinfo*/) ...{
return S_OK;
}


STDMETHOD(OnStateChange)(SCRIPTSTATE /**//*ssScriptState*/) ...{
return S_OK;
}


STDMETHOD(OnScriptError)(IActiveScriptError* pScriptError) ...{
EXCEPINFO e;
DWORD dwContext;
ULONG ulLine;
LONG lPos;
pScriptError->GetExceptionInfo(&e);
pScriptError->GetSourcePosition(&dwContext, &ulLine, &lPos);
char *pstrFormat = "An error occured while parsing script: Source: %ws Error: %08X Description: %ws Line: %d";
char pstrStr[1024];
::wsprintf( pstrStr, pstrFormat,
e.bstrSource,
e.scode,
e.bstrDescription,
ulLine+1);
::MessageBox(::GetActiveWindow(), pstrStr, _T("Compile Error"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
return S_OK;
}


STDMETHOD(OnEnterScript)() ...{
return S_OK;
}


STDMETHOD(OnLeaveScript)() ...{
return S_OK;
}
private:
TMyWin *m_pMyWin;
TMyGlobalFunc *m_pMyGlobalFunc;
int m_iRefCount;
}
;
//
=============================================================
#endif
Unit1.cpp
//
---------------------------------------------------------------------------
#include
<
vcl.h
>
#pragma
hdrstop

#include
"
Unit1.h
"
#include
"
Script.h
"
#include
<
utilcls.h
>
//
---------------------------------------------------------------------------
#pragma
package(smart_init)
#pragma
resource "*.dfm"
TForm1
*
Form1;
//
---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent
*
Owner)
: TForm(Owner)

...
{
}
//
---------------------------------------------------------------------------
void
__fastcall TForm1::btnRunClick(TObject
*
Sender)

...
{
TComInterface<IActiveScript> pAS;
pAS.CreateInstance(L"JScript");
if(!pAS) return;

TComInterface<IActiveScriptParse> pASP(pAS);
if(!pASP) return;

pASP->InitNew();

TComInterface<TMyWin> pDispatch_MyWin=new TMyWin(this);
TComInterface<TMyGlobalFunc> pDispatch_MyGlobalFunc = new TMyGlobalFunc;
TComInterface<IActiveScriptSite> pActiveScriptSite_Mine = new TMyActiveScriptSite(pDispatch_MyWin,pDispatch_MyGlobalFunc);

pAS->SetScriptSite(pActiveScriptSite_Mine);
pAS->AddNamedItem(TMyWin::Name,SCRIPTITEM_ISVISIBLE);
pAS->AddNamedItem(TMyGlobalFunc::Name,SCRIPTITEM_ISVISIBLE|SCRIPTITEM_GLOBALMEMBERS);

pASP->ParseScriptText(WideString(mmoScript->Lines->Text),
NULL,
NULL,
NULL,
0,
0,
0,
NULL,
NULL);
pAS->SetScriptState(SCRIPTSTATE_STARTED);

pAS->Close();
}
//
---------------------------------------------------------------------------
<script type="text/javascript">
</script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>