如何添加到 MFC 应用程序破坏 VBScript 的支持

您可以添加 MFC 应用程序开销很小,使用 Microsoft ActiveX 脚本技术类似于 VBA 的脚本编写功能。本文演示如何创建新的 MFC 应用程序中,或修改现有,合并了 VBScript 的支持。

更多信息

请按照以下步骤来生成并运行该示例:
  1. 创建新 MFC 对话框基于的应用程序,或使用要添加脚本的支持已有的应用程序。
  2. 向对话框,添加一个编辑框和按钮,启用"需要返回"和"多行"编辑框中的属性中的样式。
  3. 使用成员变量选项卡下类向导 (CTRL-W),IDC_EDIT1 相关联的类型名为 m_edit1 的 CEdit 成员变量。
  4. 类向导用于创建一个名为 MyScriptObject,来自 CCmdTarget,与支持自动化的新类。如果您看到一个 ODL 文件有关的警告,请单击确定。
  5. 类向导的自动化选项卡上,在下选择 MyScriptObject,,并添加下面的方法:

    long gcd(long a, long b);
    void HelpAbout() ;
    void ShowValue (LPCTSTR 提示,长时间 n) ;
  6. 实现 gcd、 HelpAbout 和 ShowValue,如下所示:
       long MyScriptObject::gcd(long a, long b) 
       {
          int l, h, t;
          if(a < b) {
             l = a;
             h = b;
          }
          else if(a > b) {
             l = b;
             h = a;
          }
          else return a;
    
          while(h%l != 0) {
             t = l;
             l = (h%l);
             h = t;
          }
          return l;
       }
    
       void MyScriptObject::HelpAbout() 
       {
          AfxMessageBox("HelpAbout: My Script Object!", 0x10000);
       }
    
       void MyScriptObject::ShowValue(LPCTSTR prompt, long n) 
       {
          CString str;
          str.Format("%s%d", prompt, n);
          AfxMessageBox(str, MB_SETFOREGROUND);
       }
    					
  7. 打开 MyScriptObject.h,并移动虚拟析构函数 ~ MyScriptObject 类的受保护的分区中的公共部分。
  8. 双击对话框按钮来创建一个处理程序函数,并实现它,如下所示:
       // Initialize our IActiveScriptSite implementation with your
       // script object's IUnknown interface...
       g_iActiveScriptSite.m_pUnkScriptObject = 
          m_myScriptObject.GetInterface(&IID_IUnknown);
    
       // Start inproc script engine, VBSCRIPT.DLL
       HRVERIFY(CoCreateInstance(CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER, 
          IID_IActiveScript, (void **)&m_iActiveScript), 
          "CoCreateInstance() for CLSID_VBScript");
    
       // Get engine's IActiveScriptParse interface.
       HRVERIFY(m_iActiveScript->QueryInterface(IID_IActiveScriptParse, 
          (void **)&m_iActiveScriptParse), 
          "QueryInterface() for IID_IActiveScriptParse");
    
       // Give engine our IActiveScriptSite interface...
       HRVERIFY(m_iActiveScript->SetScriptSite(&g_iActiveScriptSite), 
          "IActiveScript::SetScriptSite()");
    
       // Give the engine a chance to initialize itself...
       HRVERIFY(m_iActiveScriptParse->InitNew(),
          "IActiveScriptParse::InitNew()");
    
       // Add a root-level item to the engine's name space...
       HRVERIFY(m_iActiveScript->AddNamedItem(L"MyObject", 
          SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE),
          "IActiveScript::AddNamedItem()");	
    
       // Get script code...
       CString csScriptText;
       m_edit1.GetWindowText(csScriptText);
    
       // Parse the code scriptlet...
       EXCEPINFO ei;
       BSTR pParseText = csScriptText.AllocSysString();
       m_iActiveScriptParse->ParseScriptText(pParseText, L"MyObject", NULL,
          NULL, 0, 0, 0L, NULL, &ei);
    
       // Set the engine state. This line actually triggers the execution
       // of the script.
       m_iActiveScript->SetScriptState(SCRIPTSTATE_CONNECTED);
    
       // Release engine...
       m_iActiveScriptParse->Release();
       m_iActiveScript->Release();
    					
  9. 打开您 [projectname]Dlg.h 文件并将下面的成员变量添加到您的类的公共部分:
       MyScriptObject m_myScriptObject;
       IActiveScript *m_iActiveScript;
       IActiveScriptParse *m_iActiveScriptParse;
    					
  10. 也在 [projectname]Dlg.h,添加下面的 #include 语句,您的类声明之前:
       // Include ActiveX Script definitions...
       #include <activscp.h>
       // Include definition for MyScriptObject...
       #include "MyScriptObject.h"
    					
  11. 将以下代码添加到您 [只是之前的按钮处理程序实现,在 projectname]Dlg.cpp 文件:
    // Your IActiveScriptSite implementation...
    class MyActiveScriptSite : public IActiveScriptSite {
    private:
       ULONG m_dwRef; // Reference count
    public:
       IUnknown *m_pUnkScriptObject; // Pointer to your object that is exposed
                                     // to the script engine in GetItemInfo().
       
       MyActiveScriptSite::MyActiveScriptSite() {m_dwRef = 1;}
       MyActiveScriptSite::~MyActiveScriptSite() {}
       
       // IUnknown methods...
       virtual HRESULT _stdcall QueryInterface(REFIID riid, void **ppvObject) {
          *ppvObject = NULL;
          return E_NOTIMPL;
       }
       virtual ULONG _stdcall AddRef(void) {
          return ++m_dwRef;
       }
       virtual ULONG _stdcall Release(void) {
          if(--m_dwRef == 0) return 0;
          return m_dwRef;
       }
       
       // IActiveScriptSite methods...
       virtual HRESULT _stdcall GetLCID(LCID *plcid) {
          return S_OK;
       }
       
       virtual HRESULT _stdcall GetItemInfo(LPCOLESTR pstrName,
          DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti) {
    
          // Is it expecting an ITypeInfo?
          if(ppti) {
             // Default to NULL.
             *ppti = NULL;
             
             // Return if asking about ITypeInfo... 
             if(dwReturnMask & SCRIPTINFO_ITYPEINFO)
                return TYPE_E_ELEMENTNOTFOUND;
          }
          
          // Is the engine passing an IUnknown buffer?
          if(ppunkItem) {
             // Default to NULL.
             *ppunkItem = NULL;
             
             // Is Script Engine looking for an IUnknown for our object?
             if(dwReturnMask & SCRIPTINFO_IUNKNOWN) {
                // Check for our object name...
                if (!_wcsicmp(L"MyObject", pstrName)) {
                   // Provide our object.
                   *ppunkItem = m_pUnkScriptObject;
                   // Addref our object...
                   m_pUnkScriptObject->AddRef();
                }
             }
          }
          
          return S_OK;
       }
       
       virtual HRESULT __stdcall GetDocVersionString(BSTR *pbstrVersion) {
          return S_OK;
       }
       
       virtual HRESULT __stdcall OnScriptTerminate(const VARIANT *pvarResult,
          const EXCEPINFO *pexcepInfo) {
          return S_OK;
       }
       
       virtual HRESULT __stdcall OnStateChange(SCRIPTSTATE ssScriptState) {
          return S_OK;
       }
       
       virtual HRESULT __stdcall OnScriptError(
          IActiveScriptError *pscriptError) {
          static BSTR pwcErrorText;
          pscriptError->GetSourceLineText(&pwcErrorText);
    
          AfxMessageBox(
             CString("IActiveScriptSite::OnScriptError()\n") + 
             CString("Line: ") + 
             CString(pwcErrorText),
             MB_SETFOREGROUND);
          ::SysFreeString(pwcErrorText);
          return S_OK;
       }
       
       virtual HRESULT __stdcall OnEnterScript(void) {
          return S_OK;
       }
       
       virtual HRESULT __stdcall OnLeaveScript(void) {
          return S_OK;
       }
    };
    
    // Global instance of our IActiveScriptSite implementation.
    MyActiveScriptSite g_iActiveScriptSite;
    
    // Script Engine CLSIDs...
    #include <initguid.h>
    DEFINE_GUID(CLSID_VBScript, 0xb54f3741, 0x5b07, 0x11cf, 0xa4, 0xb0, 0x0,
       0xaa, 0x0, 0x4a, 0x55, 0xe8);
    DEFINE_GUID(CLSID_JScript, 0xf414c260, 0x6ac0, 0x11cf, 0xb6, 0xd1, 0x00,
       0xaa, 0x00, 0xbb, 0xbb, 0x58);
    
    // Ole-initialization class.
    class OleInitClass {
    public:
       OleInitClass() {
          OleInitialize(NULL);
       }
       ~OleInitClass() {
          OleUninitialize();
       }
    };
    // This global class calls OleInitialize() at
    // application startup, and calls OleUninitialize()
    // at application exit...
    OleInitClass g_OleInitClass;
    
    void HRVERIFY(HRESULT hr, char * msg)
    {
       if(FAILED(hr)) {
          CString str;
          str.Format("Error: 0x%08lx (%s)", hr, msg);
          AfxMessageBox(str, 0x10000);
          _exit(0);
       }
    
    }
    					
  12. 编译并运行。

生成项目后,运行它,向您的应用程序编辑框中,添加下面的 VBScript 然后单击的按钮:
   dim x
   dim y
   dim z
   x = 101*199
   y = 313*199
   z = gcd(x, y)

   ShowValue "gcd(" & x & ", " & y & ") = ", z

   HelpAbout
				


基本工作流如下所示:
  1. 首先,VBScript 引擎,vbscript.dll,并获得 IActiveScript 和 IActiveScriptParse 接口。
  2. 您授予的 VBScript 引擎 IActiveScriptSite,引擎使用更高版本来获取,然后对您的对象调用的实现。
  3. 您添加的对象的实现,并希望对脚本可通过调用 IActiveScript::AddNamedItem()。
  4. 您提供的脚本文本通过 IActiveScriptParse::ParseScriptText() 执行。请注意这实际上还不是在运行该脚本。
  5. 脚本引擎将立即连接到您的 IActiveScriptSite::GetItemInfo() 无法识别,若要获取的接口指针的任何对象。
  6. IActiveScript::SetScriptState() 与 SCRIPT_STATE_CONNECTED 以运行该脚本,则调用。
  7. VBScript 引擎分析为您的脚本中的文本,以及当它遇到的方法调用或属性的引用时,它委托给您提供的接口的实现。

<linker : http://support.microsoft.com/kb/221992/zh-cn>

<linker : exmaple code : http://www.pudn.com/downloads70/sourcecode/windows/other/detail251422.html>

posted @ 2013-06-23 23:57  MMLoveMeMM  阅读(569)  评论(0)    收藏  举报