如何在我们的程序中使用jscript脚本(zz)

原文地址:http://www.cppprog.com/2009/0406/99.html

在CSDN上看到有不少人问怎样才能象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脚本:

  1. var bForward = true;
  2. for(var i=0;i<ScreenWidth-200;i+=100)
  3. {
  4. for(var j=0;j<ScreenHeight-200;j+=10)
  5.     {
  6. var x = i;
  7. var y = bForward? j : (ScreenHeight-200-j)
  8.         MyWin.MoveTo(x,y);
  9.         MyWin.Caption = "X:" + x + " Y:"+y;
  10.         MyWin.Color = (x<<16|y)&0xffffff;
  11.         Sleep(10);
  12.     }
  13.     bForward = !bForward;
  14. }

此脚本的目的是让一个叫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这三个全局函数:

  1. struct TMyGlobalFunc : TDispatch{
  2. enum {itemScreenWidth,itemScreenHeight,itemSleep};
  3. static wchar_t Name[];
  4.     STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,
  5.             DISPID *rgDispId){
  6. if(lstrcmpW(rgszNames[0],L"ScreenWidth") == 0){
  7.             *rgDispId = itemScreenWidth;
  8.         }
  9. else if(lstrcmpW(rgszNames[0],L"ScreenHeight") == 0) {
  10.             *rgDispId = itemScreenHeight;
  11.         }
  12. else if(lstrcmpW(rgszNames[0],L"Sleep") == 0) {
  13.             *rgDispId = itemSleep;
  14.         }
  15. else
  16. return E_NOTIMPL;
  17. return S_OK;
  18.     }
  19.     STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
  20.             DISPPARAMS *pDispParams,
  21.             VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr){
  22. switch(dispIdMember)
  23.         {
  24. case itemScreenWidth:
  25.                 pVarResult->vt=VT_I4;
  26.                 pVarResult->intVal = Screen->Width;
  27. break;
  28. case itemScreenHeight:
  29.                 pVarResult->vt=VT_I4;
  30.                 pVarResult->intVal = Screen->Height;
  31. break;
  32. case itemSleep:
  33. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  34. if(pDispParams->rgvarg[0].vt != VT_I4) {
  35.                     *puArgErr = 0;
  36. return DISP_E_TYPEMISMATCH;
  37.                 }
  38.                 Application->ProcessMessages();
  39.                 Sleep(pDispParams->rgvarg[0].intVal);
  40. break;
  41. default:
  42. return DISP_E_MEMBERNOTFOUND;
  43.         }
  44. return S_OK;
  45.     }
  46. };
  47. wchar_t TMyGlobalFunc::Name[]=L"MyGlobalFunc";

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

  1. struct TMyWin : TDispatch{
  2. enum {itemCaption,itemColor,itemMoveTo};
  3. static wchar_t Name[];
  4. // IDispatch
  5.     STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,
  6.                                 DISPID *rgDispId){
  7. if(lstrcmpW(rgszNames[0],L"Caption") == 0) {
  8.             *rgDispId = itemCaption;
  9.         }
  10. else if(lstrcmpW(rgszNames[0],L"Color") == 0) {
  11.             *rgDispId = itemColor;
  12.         }
  13. else if(lstrcmpW(rgszNames[0],L"MoveTo") == 0) {
  14.             *rgDispId = itemMoveTo;
  15.         }
  16. else
  17. return E_NOTIMPL;
  18. return S_OK;
  19.     }
  20.     STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
  21.                       DISPPARAMS *pDispParams,
  22.                       VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr){
  23. switch(dispIdMember)
  24.         {
  25. case itemCaption:
  26.           {
  27. if(wFlags==DISPATCH_PROPERTYGET)
  28.             {
  29.                 pVarResult->vt = VT_BSTR;
  30.                 pVarResult->bstrVal = GetCaption();
  31.             }
  32. else if(wFlags==DISPATCH_PROPERTYPUT)
  33.             {
  34. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  35. if(pDispParams->rgvarg[0].vt != VT_BSTR) {
  36.                     *puArgErr = 0;
  37. return DISP_E_TYPEMISMATCH;
  38.                 }
  39.                 SetCaption(pDispParams->rgvarg[0].bstrVal);
  40.             }
  41. else
  42. return DISP_E_MEMBERNOTFOUND;
  43. break;
  44.           }
  45. case itemColor:
  46.           {
  47. if(wFlags==DISPATCH_PROPERTYGET)
  48.             {
  49.                 pVarResult->vt = VT_I4;
  50.                 pVarResult->intVal = GetColor();
  51.             }
  52. else if(wFlags==DISPATCH_PROPERTYPUT)
  53.             {
  54. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  55. if(pDispParams->rgvarg[0].vt != VT_I4) {
  56.                     *puArgErr = 0;
  57. return DISP_E_TYPEMISMATCH;
  58.                 }
  59.                 SetColor(pDispParams->rgvarg[0].intVal);
  60.             }
  61. else
  62. return DISP_E_MEMBERNOTFOUND;
  63. break;
  64.           }
  65. case itemMoveTo:
  66.           {
  67. if(wFlags==DISPATCH_METHOD)
  68.             {
  69. if(pDispParams->cArgs!=2) return DISP_E_BADPARAMCOUNT;
  70. if(pDispParams->rgvarg[0].vt != VT_I4) {
  71.                     *puArgErr = 0;
  72. return DISP_E_TYPEMISMATCH;
  73.                 }
  74. else if(pDispParams->rgvarg[1].vt != VT_I4){
  75.                     *puArgErr = 1;
  76. return DISP_E_TYPEMISMATCH;
  77.                 }
  78.                 MoveTo( pDispParams->rgvarg[1].intVal,
  79.                         pDispParams->rgvarg[0].intVal);
  80.             }
  81. else
  82. return DISP_E_MEMBERNOTFOUND;
  83. break;
  84.           }
  85. default:
  86. return DISP_E_MEMBERNOTFOUND;
  87.         }
  88. return S_OK;
  89.     }
  90. //  TMyWin上所有的方法属性都对这个TForm *fm_Opt操作
  91.     TMyWin(TForm *fm_Opt) : TDispatch(),m_Form(fm_Opt){ ; }  
  92.     BSTR GetCaption(){
  93. return WideString(m_Form->Caption).Detach();
  94.     }
  95. void SetCaption(BSTR bstrCaption){
  96.         m_Form->Caption = bstrCaption;
  97.     }
  98. int GetColor(){
  99. return (int)m_Form->Color;
  100.     }
  101. void SetColor(int iColor){
  102.         m_Form->Color = TColor(iColor);
  103.     }
  104. void MoveTo(int X,int Y){
  105.         m_Form->Left=X;
  106.         m_Form->Top=Y;
  107.     }
  108. private:
  109.     TForm *m_Form;
  110. };
  111. wchar_t TMyWin::Name[]=L"MyWin";

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

  1. struct TMyActiveScriptSite
  2.     : IActiveScriptSite
  3. {
  4.     TMyActiveScriptSite(TMyWin *pMyWin,TMyGlobalFunc *pMyGlobalFunc)
  5.         : m_iRefCount(1),m_pMyWin(pMyWin),m_pMyGlobalFunc(pMyGlobalFunc){
  6.     }
  7. // IUNKnown,不得不写
  8. HRESULT __stdcall QueryInterface(REFIID iid, void **ppv){
  9. if(iid==IID_IUnknown||iid==IID_IActiveScriptSite)
  10.         {
  11.             *ppv=this;
  12.             AddRef();
  13. return S_OK;
  14.         }
  15.         *ppv=NULL;
  16. return E_NOINTERFACE;
  17.     }
  18. ULONG __stdcall AddRef(void) {
  19. return ++m_iRefCount;
  20.     }
  21. ULONG __stdcall Release(void) {
  22. if(--m_iRefCount==0){
  23. delete this;
  24. return 0;
  25.         }
  26. return m_iRefCount;
  27.     }
  28. // IActiveScriptSite
  29.     STDMETHOD(GetLCID)(LCID* /**//*plcid*/) {
  30. return E_NOTIMPL;
  31.     }
  32. //主要的就是这个
  33.     STDMETHOD(GetItemInfo)(LPCOLESTR pstrName,
  34. DWORD dwReturnMask,
  35.                           IUnknown** ppiunkItem,
  36.                           ITypeInfo** ppti) {
  37. if( (dwReturnMask & SCRIPTINFO_ITYPEINFO)!=0 ){
  38.             *ppti = NULL;
  39. return E_FAIL;
  40.         }
  41. if( (dwReturnMask & SCRIPTINFO_IUNKNOWN)==0 ) return E_FAIL;
  42. if( ppiunkItem==NULL ) return E_POINTER;
  43.         *ppiunkItem = NULL;
  44. if( lstrcmpW( pstrName, TMyWin::Name )==0 ) {
  45. //[AS]要MyWin,送上!
  46.             m_pMyWin->AddRef();
  47.             *ppiunkItem = m_pMyWin;
  48. return S_OK;
  49.         }
  50. else if( lstrcmpW( pstrName, TMyGlobalFunc::Name )==0 ) { 
  51. //[AS]要MyGlobalFunc,送上!
  52.             m_pMyGlobalFunc->AddRef();
  53.             *ppiunkItem = m_pMyGlobalFunc;
  54. return S_OK;
  55.         }
  56. return E_FAIL;   //要其它的,没有!
  57.    }
  58.    STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) {
  59. if( pbstrVersion==NULL ) return E_POINTER;
  60.       *pbstrVersion = ::SysAllocString(OLESTR("Script 1.0"));
  61. return S_OK;
  62.    }
  63.    STDMETHOD(OnScriptTerminate)(
  64. const VARIANT* /**//*pvarResult*/,
  65. const EXCEPINFO* /**//*pexcepinfo*/) {
  66. return S_OK;
  67.    }
  68.    STDMETHOD(OnStateChange)(SCRIPTSTATE /**//*ssScriptState*/) {
  69. return S_OK;
  70.    }
  71. // 脚本里有错误时会调用OnScriptError
  72.    STDMETHOD(OnScriptError)(IActiveScriptError* pScriptError) {
  73.       EXCEPINFO e;
  74. DWORD dwContext;
  75. ULONG ulLine;
  76. LONG lPos;
  77.       pScriptError->GetExceptionInfo(&e);
  78.       pScriptError->GetSourcePosition(&dwContext, &ulLine, &lPos);
  79. char *pstrFormat = "An error occured while parsing script:"
  80. " Source: %ws Error: %08X Description: %ws Line: %d";
  81. char pstrStr[1024];
  82.       ::wsprintf( pstrStr, pstrFormat,
  83.          e.bstrSource,
  84.          e.scode,
  85.          e.bstrDescription,
  86.          ulLine+1);
  87.       ::MessageBox(::GetActiveWindow(), pstrStr,
  88.         _T("Compile Error"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  89. return S_OK;
  90.    }
  91.    STDMETHOD(OnEnterScript)() {
  92. return S_OK;
  93.    }
  94.    STDMETHOD(OnLeaveScript)() {
  95. return S_OK;
  96.    }
  97. private:
  98.     TMyWin *m_pMyWin;
  99.     TMyGlobalFunc *m_pMyGlobalFunc;
  100. int m_iRefCount;
  101. };

万事俱备,就等执行了:
打开BCB,新建一VCL Form Application。
在默认的Form1上加入一个TMemo改名为:mmoScript;加入一个TButton改名为btnRun。btnRun->OnClick代码:
偷懒用到了TComInterface,要包含: #include <utilcls.h>

  1. void __fastcall TForm1::btnRunClick(TObject *Sender)
  2. {
  3.     TComInterface<IActiveScript> pAS;
  4. // 第一步,实例化Jscript(同学们也可以试试VBScript)
  5.     pAS.CreateInstance(L"JScript");   
  6. if(!pAS) return;
  7.     TComInterface<IActiveScriptParse> pASP(pAS);
  8. if(!pASP) return;
  9.     pASP->InitNew();
  10. // 我们的劳动成果在这里
  11.     TComInterface<TMyWin> pDispatch_MyWin = new TMyWin(this);
  12.     TComInterface<TMyGlobalFunc> pDispatch_MyGlobalFunc = new TMyGlobalFunc;
  13.     TComInterface<TMyActiveScriptSite> pActiveScriptSite_Mine = 
  14. new TMyActiveScriptSite(pDispatch_MyWin,pDispatch_MyGlobalFunc);
  15. //第二步,告诉IActiveScript谁来解释脚本中的对象
  16.   pAS->SetScriptSite(pActiveScriptSite_Mine);
  17. //第三步,告诉IActiveScript脚本里会用到哪些对象
  18.     pAS->AddNamedItem(TMyWin::Name,SCRIPTITEM_ISVISIBLE);  //会用到”MyWin”
  19. //多了一个SCRIPTITEM_GLOBALMEMBERS,意思是如果遇到全局函数就向”MyGlobalFunc”要。
  20.     pAS->AddNamedItem(TMyGlobalFunc::Name,
  21.         SCRIPTITEM_ISVISIBLE|SCRIPTITEM_GLOBALMEMBERS);
  22. //第四步,装入脚本
  23.     pASP->ParseScriptText(WideString(mmoScript->Lines->Text),
  24.                                   NULL,
  25.                                   NULL,
  26.                                   NULL,
  27.                                   0,
  28.                                   0,
  29.                                   0,
  30.                                   NULL,
  31.                                   NULL);
  32. //第五步,运行脚本
  33.   pAS->SetScriptState(SCRIPTSTATE_STARTED);
  34.     pAS->Close();
  35. }

编译,运行。
把写的Jscript代码拷贝到mmoScript里然后按btnRun运行可以看到效果。当然也可以修改脚本弄点更好玩的花样出来,呵呵。
最后还要多说一句关于ParseScriptText,用好它后面的几个参数。看MSDN,修改其中一个参数这段代码就可以用作表态式解析了。
附上完整代码:
Script.h

  1. #ifndef SCRIPT_H
  2. #define SCRIPT_H
  3. //=============================================================
  4. #include <tchar.h>
  5. #include <activscp.h>
  6. // TDispatch:简单实现IDispath的所有方法,用于作自动化对象的基类。
  7. struct TDispatch : IDispatch{
  8.     TDispatch():m_iRefCount(1){;}
  9.     ~TDispatch(){;}
  10. // IUNKnown
  11. HRESULT __stdcall QueryInterface(REFIID iid, void **ppv){
  12. if(iid==IID_IUnknown||iid==IID_IDispatch)
  13.         {
  14.             *ppv=this;
  15.             AddRef();
  16. return S_OK;
  17.         }
  18.         *ppv=NULL;
  19. return E_NOINTERFACE;
  20.     }
  21. ULONG __stdcall AddRef(void) {
  22. return ++m_iRefCount;
  23.     }
  24. ULONG __stdcall Release(void) {
  25. if(--m_iRefCount==0){
  26. delete this;
  27. return 0;
  28.         }
  29. return m_iRefCount;
  30.     }
  31. // IDispatch
  32.     STDMETHOD(GetTypeInfoCount)(UINT *pctinfo){return S_OK;}
  33.     STDMETHOD(GetTypeInfo)(UINT iTInfo,
  34. LCID lcid,ITypeInfo **ppTInfo){return S_OK;}
  35.     STDMETHOD(GetIDsOfNames)(REFIID riid,
  36.             LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId){
  37. return E_NOTIMPL;
  38.     }
  39.     STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,
  40. LCID lcid,WORD wFlags,
  41.             DISPPARAMS *pDispParams,
  42.             VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr){
  43. return S_OK;
  44.     }
  45. private:
  46. int m_iRefCount;
  47. };
  48. // TMyWin,实现MyWin对象类,解释Caption,Color属性,MoveTo方法
  49. struct TMyWin : TDispatch{
  50. enum {itemCaption,itemColor,itemMoveTo};
  51. static wchar_t Name[];
  52. // IDispatch
  53.     STDMETHOD(GetIDsOfNames)(REFIID riid,
  54.             LPOLESTR *rgszNames,UINT cNames,LCID lcid,
  55.             DISPID *rgDispId){
  56. if(lstrcmpW(rgszNames[0],L"Caption") == 0)
  57.         {
  58.             *rgDispId = itemCaption;
  59.         }
  60. else if(lstrcmpW(rgszNames[0],L"Color") == 0)
  61.         {
  62.             *rgDispId = itemColor;
  63.         }
  64. else if(lstrcmpW(rgszNames[0],L"MoveTo") == 0)
  65.         {
  66.             *rgDispId = itemMoveTo;
  67.         }
  68. else
  69. return E_NOTIMPL;
  70. return S_OK;
  71.     }
  72.     STDMETHOD(Invoke)(DISPID dispIdMember,
  73.             REFIID riid,LCID lcid,WORD wFlags,
  74.             DISPPARAMS *pDispParams,
  75.             VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr){
  76. switch(dispIdMember)
  77.         {
  78. case itemCaption:
  79.                 {
  80. if(wFlags==DISPATCH_PROPERTYGET)
  81.                     {
  82.                         pVarResult->vt = VT_BSTR;
  83.                         pVarResult->bstrVal = GetCaption();
  84.                     }
  85. else if(wFlags==DISPATCH_PROPERTYPUT)
  86.                     {
  87. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  88. if(pDispParams->rgvarg[0].vt != VT_BSTR) {
  89.                             *puArgErr = 0;
  90. return DISP_E_TYPEMISMATCH;
  91.                         }
  92.                         SetCaption(pDispParams->rgvarg[0].bstrVal);
  93.                     }
  94. else
  95. return DISP_E_MEMBERNOTFOUND;
  96. break;
  97.                 }
  98. case itemColor:
  99.                 {
  100. if(wFlags==DISPATCH_PROPERTYGET)
  101.                     {
  102.                         pVarResult->vt = VT_I4;
  103.                         pVarResult->intVal = GetColor();
  104.                     }
  105. else if(wFlags==DISPATCH_PROPERTYPUT)
  106.                     {
  107. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  108. if(pDispParams->rgvarg[0].vt != VT_I4) {
  109.                             *puArgErr = 0;
  110. return DISP_E_TYPEMISMATCH;
  111.                         }
  112.                         SetColor(pDispParams->rgvarg[0].intVal);
  113.                     }
  114. else
  115. return DISP_E_MEMBERNOTFOUND;
  116. break;
  117.                 }
  118. case itemMoveTo:
  119.                 {
  120. if(wFlags==DISPATCH_METHOD)
  121.                     {
  122. if(pDispParams->cArgs!=2) return DISP_E_BADPARAMCOUNT;
  123. if(pDispParams->rgvarg[0].vt != VT_I4) {
  124.                             *puArgErr = 0;
  125. return DISP_E_TYPEMISMATCH;
  126.                         }
  127. else if(pDispParams->rgvarg[1].vt != VT_I4){
  128.                             *puArgErr = 1;
  129. return DISP_E_TYPEMISMATCH;
  130.                         }
  131.                         MoveTo( pDispParams->rgvarg[1].intVal,
  132.                                 pDispParams->rgvarg[0].intVal);
  133.                     }
  134. else
  135. return DISP_E_MEMBERNOTFOUND;
  136. break;
  137.                 }
  138. default:
  139. return DISP_E_MEMBERNOTFOUND;
  140.         }
  141. return S_OK;
  142.     }
  143. //  TMyWin
  144.     TMyWin(TForm *fm_Opt) : TDispatch(),m_Form(fm_Opt){ ; }
  145.     BSTR GetCaption(){
  146. return WideString(m_Form->Caption).Detach();
  147.     }
  148. void SetCaption(BSTR bstrCaption){
  149.         m_Form->Caption = bstrCaption;
  150.     }
  151. int GetColor(){
  152. return (int)m_Form->Color;
  153.     }
  154. void SetColor(int iColor){
  155.         m_Form->Color = TColor(iColor);
  156.     }
  157. void MoveTo(int X,int Y){
  158.         m_Form->Left=X;
  159.         m_Form->Top=Y;
  160.     }
  161. private:
  162.     TForm *m_Form;
  163. };
  164. wchar_t TMyWin::Name[]=L"MyWin";
  165. struct TMyGlobalFunc : TDispatch{
  166. enum {itemScreenWidth,itemScreenHeight,itemSleep};
  167. static wchar_t Name[];
  168.     STDMETHOD(GetIDsOfNames)(REFIID riid,
  169.             LPOLESTR *rgszNames,UINT cNames,LCID lcid,
  170.             DISPID *rgDispId){
  171. if(lstrcmpW(rgszNames[0],L"ScreenWidth") == 0)
  172.         {
  173.             *rgDispId = itemScreenWidth;
  174.         }
  175. else if(lstrcmpW(rgszNames[0],L"ScreenHeight") == 0)
  176.         {
  177.             *rgDispId = itemScreenHeight;
  178.         }
  179. else if(lstrcmpW(rgszNames[0],L"Sleep") == 0)
  180.         {
  181.             *rgDispId = itemSleep;
  182.         }
  183. else
  184. return E_NOTIMPL;
  185. return S_OK;
  186.     }
  187.     STDMETHOD(Invoke)(DISPID dispIdMember,
  188.             REFIID riid,LCID lcid,WORD wFlags,
  189.             DISPPARAMS *pDispParams,
  190.             VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr){
  191. switch(dispIdMember)
  192.         {
  193. case itemScreenWidth:
  194.                 pVarResult->vt=VT_I4;
  195.                 pVarResult->intVal = Screen->Width;
  196. break;
  197. case itemScreenHeight:
  198.                 pVarResult->vt=VT_I4;
  199.                 pVarResult->intVal = Screen->Height;
  200. break;
  201. case itemSleep:
  202. if(pDispParams->cArgs!=1) return DISP_E_BADPARAMCOUNT;
  203. if(pDispParams->rgvarg[0].vt != VT_I4) {
  204.                     *puArgErr = 0;
  205. return DISP_E_TYPEMISMATCH;
  206.                 }
  207.                 Application->ProcessMessages();
  208.                 Sleep(pDispParams->rgvarg[0].intVal);
  209. break;
  210. default:
  211. return DISP_E_MEMBERNOTFOUND;
  212.         }
  213. return S_OK;
  214.     }
  215. };
  216. wchar_t TMyGlobalFunc::Name[]=L"MyGlobalFunc";
  217. struct TMyActiveScriptSite
  218. : IActiveScriptSite
  219. {
  220.     TMyActiveScriptSite(TMyWin *pMyWin,TMyGlobalFunc *pMyGlobalFunc)
  221.         : m_iRefCount(1),m_pMyWin(pMyWin),
  222.         m_pMyGlobalFunc(pMyGlobalFunc){
  223.         }
  224. // IUNKnown
  225. HRESULT __stdcall QueryInterface(REFIID iid, void **ppv){
  226. if(iid==IID_IUnknown||iid==IID_IActiveScriptSite)
  227.         {
  228.             *ppv=this;
  229.             AddRef();
  230. return S_OK;
  231.         }
  232.         *ppv=NULL;
  233. return E_NOINTERFACE;
  234.     }
  235. ULONG __stdcall AddRef(void) {
  236. return ++m_iRefCount;
  237.     }
  238. ULONG __stdcall Release(void) {
  239. if(--m_iRefCount==0){
  240. delete this;
  241. return 0;
  242.         }
  243. return m_iRefCount;
  244.     }
  245. // IActiveScriptSite
  246.     STDMETHOD(GetLCID)(LCID* /**//*plcid*/) {
  247. return E_NOTIMPL;
  248.     }
  249.     STDMETHOD(GetItemInfo)(LPCOLESTR pstrName,
  250. DWORD dwReturnMask,
  251.             IUnknown** ppiunkItem,
  252.             ITypeInfo** ppti) {
  253. if( (dwReturnMask & SCRIPTINFO_ITYPEINFO)!=0 ){
  254.             *ppti = NULL;
  255. return E_FAIL;
  256.         }
  257. if( (dwReturnMask & SCRIPTINFO_IUNKNOWN)==0 ) return E_FAIL;
  258. if( ppiunkItem==NULL ) return E_POINTER;
  259.         *ppiunkItem = NULL;
  260. if( lstrcmpW( pstrName, TMyWin::Name )==0 ) {
  261.             m_pMyWin->AddRef();
  262.             *ppiunkItem = m_pMyWin;
  263. return S_OK;
  264.         }
  265. else if( lstrcmpW( pstrName, TMyGlobalFunc::Name )==0 ) {
  266.             m_pMyGlobalFunc->AddRef();
  267.             *ppiunkItem = m_pMyGlobalFunc;
  268. return S_OK;
  269.         }
  270. return E_FAIL;
  271.     }
  272.     STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) {
  273. if( pbstrVersion==NULL ) return E_POINTER;
  274.         *pbstrVersion = ::SysAllocString(OLESTR("Script 1.0"));
  275. return S_OK;
  276.     }
  277.     STDMETHOD(OnScriptTerminate)(
  278. const VARIANT* /**//*pvarResult*/,
  279. const EXCEPINFO* /**//*pexcepinfo*/) {
  280. return S_OK;
  281.     }
  282.     STDMETHOD(OnStateChange)(SCRIPTSTATE /**//*ssScriptState*/) {
  283. return S_OK;
  284.     }
  285.     STDMETHOD(OnScriptError)(IActiveScriptError* pScriptError) {
  286.         EXCEPINFO e;
  287. DWORD dwContext;
  288. ULONG ulLine;
  289. LONG lPos;
  290.         pScriptError->GetExceptionInfo(&e);
  291.         pScriptError->GetSourcePosition(&dwContext, &ulLine, &lPos);
  292. char *pstrFormat = "An error occured while parsing script:"
  293. " Source: %ws Error: %08X Description: %ws Line: %d";
  294. char pstrStr[1024];
  295.         ::wsprintf( pstrStr, pstrFormat,
  296.                 e.bstrSource,
  297.                 e.scode,
  298.                 e.bstrDescription,
  299.                 ulLine+1);
  300.         ::MessageBox(::GetActiveWindow(), pstrStr,
  301.             _T("Compile Error"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  302. return S_OK;
  303.     }
  304.     STDMETHOD(OnEnterScript)() {
  305. return S_OK;
  306.     }
  307.     STDMETHOD(OnLeaveScript)() {
  308. return S_OK;
  309.     }
  310. private:
  311.     TMyWin *m_pMyWin;
  312.     TMyGlobalFunc *m_pMyGlobalFunc;
  313. int m_iRefCount;
  314. };
  315. //=============================================================
  316. #endif

Unit1.cpp

  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Unit1.h"
  5. #include "Script.h"
  6. #include <utilcls.h>
  7. //---------------------------------------------------------------------------
  8. #pragma package(smart_init)
  9. #pragma resource "*.dfm"
  10. TForm1 *Form1;
  11. //---------------------------------------------------------------------------
  12. __fastcall TForm1::TForm1(TComponent* Owner)
  13.     : TForm(Owner)
  14. {
  15. }
  16. //---------------------------------------------------------------------------
  17. void __fastcall TForm1::btnRunClick(TObject *Sender)
  18. {
  19.     TComInterface<IActiveScript> pAS;
  20.     pAS.CreateInstance(L"JScript");
  21. if(!pAS) return;
  22.     TComInterface<IActiveScriptParse> pASP(pAS);
  23. if(!pASP) return;
  24.     pASP->InitNew();
  25.     TComInterface<TMyWin> pDispatch_MyWin=new TMyWin(this);
  26.     TComInterface<TMyGlobalFunc> pDispatch_MyGlobalFunc = new TMyGlobalFunc;
  27.     TComInterface<IActiveScriptSite> pActiveScriptSite_Mine = 
  28. new TMyActiveScriptSite(pDispatch_MyWin,pDispatch_MyGlobalFunc);
  29.     pAS->SetScriptSite(pActiveScriptSite_Mine);
  30.     pAS->AddNamedItem(TMyWin::Name,SCRIPTITEM_ISVISIBLE);
  31.     pAS->AddNamedItem(TMyGlobalFunc::Name,
  32.         SCRIPTITEM_ISVISIBLE|SCRIPTITEM_GLOBALMEMBERS);
  33.     pASP->ParseScriptText(WideString(mmoScript->Lines->Text),
  34.                                   NULL,
  35.                                   NULL,
  36.                                   NULL,
  37.                                   0,
  38.                                   0,
  39.                                   0,
  40.                                   NULL,
  41.                                   NULL);
  42.     pAS->SetScriptState(SCRIPTSTATE_STARTED);
  43.     pAS->Close();
  44. }
  45. //---------------------------------------------------------------------------
posted @ 2010-06-07 22:54  拿走不谢  阅读(1155)  评论(0编辑  收藏  举报