在自己的程序中加入脚本支持 —— ActiveX Scripting技术

<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

<转载时请注明出处--Waiting4you>
  在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脚本:

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只帮我们解决脚本语言上的问题,我们来处理对象和函数。在这个脚本里,我们的任务有:ScreenWidthScreenHeightSleepMyWin对象以及它的方法属性
这里还得说一下IDispatch的调用过程:比如当[AS]执行到MyWin.MoveTo(x,y);时,它先得到MyWin的IDispatch接口(它是怎么得到的?后面会讲先按下不提),然后调用IDispatchGetIDsOfNames(riid,L"MoveTo",1,lcid,&rgDispId)获得MoveTo对应的"Member Id"(rgDispId参数)。再用这个"Member Id"去调用Invoke(rgDispId,...)。所以我们只需关注GetIDsOfNamesInvoke两个方法即可。

先编写一个TMyGlobalFunc来处理ScreenWidthScreenHeightSleep这三个全局函数:

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!=1return 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!=1return 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!=1return 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!=2return 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!=1return 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!=1return 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!=2return 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!=1return 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>

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值