ActiveX Scripting技术(三)

    技术2026-06-05  7

    ActiveX Scripting技术(三)(接上期)然后我们看看类CScriptHo st中接口IActiveS criptSite的成员函数GetItemInfo的实现,因为引 擎调用GetItemInfo函数获取其名字空间中名字项的信息,所以我们要 在此函数中把应用系统的对象暴露给引擎和脚本,代码如下:     STDMETHODIMP CScriptHost::GetItemInfo(LPCOLESTR pstrName ,DWORD dwReturnM ask,IUnknown **ppiunkItem, ITypeInfo **ppti )     {     HRESULT hr = S_OK;     // initialize the sent-in pointers     if(dwReturnMask & SCRIPTINFO_ITYPEINFO)     {     if(ppti == NULL)     return E_INVALIDARG;     *ppti = NULL;     }     if(dwReturnMask & SCRIPTINFO_IUNKNOWN)     {     if(ppiunkItem == NULL)     return E_INVALIDARG;     *ppiunkItem = NULL;     }     if(!_wcsicmp(m_pNamedItem, pstrName))     {     if(dwReturnMask & SCRIPTINFO_IUNKNOWN)     {     // give out the object's IUnknown pointer     *ppiunkItem = m_lpUnkCtrl;     static_cast(*ppiunkItem)- AddRef();     }     if(dwReturnMask & SCRIPTINFO_ITYPEINFO)     {     IProvideClassInfo* pClsInfo = NULL;     hr = m_lpUnkCtrl- QueryInterface(IID_IProvideClassInfo, (void**)&pClsInf o);     if(pClsInfo != NULL)     {     hr = pClsInfo- GetClassInfo(ppti);     pClsInfo- Release();     }     }     }     return hr;     }     函数GetItemInfo首先对输出参数ppiunkItem和ppti进行有效性 检查,然后判断是否输入的名字与应用支持的受控对象的名字一致,如 果一致的话,则根据参数dwReturnMask 所指示的标志,把对象的IUnkn own接口或者对象的类型信息通过输出参数传递给引擎,供引擎解释执 行脚本代码使用。     我们再看类CScriptHost中接口IActiveScriptSiteWindow的成员 函数GetWindow的实现。函数比较简单,只是把应用系统的窗口句柄通 过输出参数传递给引擎,代码如下:     HRESULT CScriptHost::GetWindow(HWND *phwnd)     {     if (m_Wnd != NULL) {     *phwnd = m_Wnd;     return S_OK;     } else     return E_FAIL;     }     类CScriptHost的其他成员函数都比较简单,有的接口成员函数可 以不实现,仅仅返回S_OK或者E_NOTIMPL即可,其代码不再一一列举。     CScriptHost提供了应用系统为支持脚本代码运行所做的基本工 作,CScriptHost为引擎提供了应用系统的必要信息。CScriptHost类 是一个通用的类,如果应用系统只有一个Automation对象暴露给脚本 代码,则可以用CScriptHost类快速实现对脚本代码的支持。如果应用 系统有多个Automation对象要暴露给脚本代码,则需要对上面介绍的C ScriptHo st类作些修改,使其支持多个名字项的处理。     四、ActiveX Scripting实例     在这一节,我们通过一个实例来说明如何利用上节提供的CScript Host类为应用程序加上脚本特性。例程序很简单,只是一个基于对话 框的应用,但对话框中有一个日历控制,这是Microsoft提供的ActiveX 控制,它本身也是一个Automation对象,我们将在脚本代码中对该日历 对象进行控制,并且在脚本代码中响应日历控制的一些事件。图3是例 程序的运行界面图。 图3 例程序运行界面图     创建例程序的过程并不复杂,利用Microsoft Visual C++ 5.0(或 6.0)提供的AppWiz ard和ClassWizard可以很快创建工程,并添加各项 功能,下面是其操作过程。     (1)首先我们创建一个MFC工程,因为例程序比较简单,所以我们选 择了基于对话框的应用类型。工程名为Script,对话框类名为CScript Dlg。     (2)然后我们在对话框资源模板中添加日历控制,打开对话框模板 ,用右键单击,从菜单中选择"Insert ActiveX Control"命令,选择Cal endar Control,然后调整大小合适即可,并设置控制的ID为IDC_CONTR OL1。     (3)在对话框模板中添加两个按钮"Load Script"和"Run Script" 放在适当的位置上。     (4)把上一节完成的文件ScriptHost.h和ScriptHost.cpp加入到 工程中。     (5)在类CScriptDlg中加入数据成员m_pScHost,其类型为CScript Host *。     (6)用ClassWizard生成按钮"Load Script"的消息控制函数,编写 代码如下。     void CScriptDlg::OnLoadscript()     {     CFileDialog dlg(TRUE, "*.txt","*.txt",OFN_HIDEREADONLY |     OFN_OVERWRITEPROMPT,"Text files (*.txt)");     if(dlg.DoModal()==IDOK)     {     CString strPath;     strPath = dlg.GetPathName();     if (strPath.IsEmpty())     return;     if (m_pScHost != NULL)     m_pScHost-m_ps-Close();     CWnd *pCalander = GetDlgItem(IDC_CONTROL1);     m_pUnknownCtrl = pCalander- GetControlUnknown();     m_pScHost = new CScriptHost(m_pUnknownCtrl, L"control", m_hWnd);     HRESULT hr = m_pScHost-CreateScriptEngine();     hr = m_pScHost- ParseFile(strPath,L"control");     GetDlgItem(IDC_RUNSCRIPT)-EnableWindow(TRUE);     GetDlgItem(IDC_RUNSCRIPT)- SetWindowText("Run Script");     return;     }     return;     }     在消息控制函数OnLoadscript中,首先打开标准文件对话框,待用 户选中脚本文件后,取到文件名,放到变量strPath中,如果原先已经存 在引擎对象,则先关闭引擎对象。     然后通过CWnd::GetControlUnknown函数取出日历控制的IUnknow n接口指针。完成了这些准备工作后,再构造一个CScriptHost对象,把 控制的IUnknown接口指针、控制名以及对话框的窗口句柄传到CScrip tHost对象中,然后调用其CreateScriptEngine成员函数创建脚本引擎 对象,创建完成后,再调用ParseFile成员函数装入脚本文件。装入脚 本之后, 设置"Run Script"按钮使其接收运行脚本的命令。注意,在O nLoadscript函数返回后,脚本引擎已经创建完成,脚本文件也已经装 入到引擎中,但这时脚本代码并没有被运行。     (7)用ClassWizard生成按钮"Run Script"的消息控制函数,编写 代码如下。     void CScriptDlg::OnRunscript()     {     if (m_pScHost != NULL) {     SCRIPTSTATE ss;     if (FAILED(m_pScHost- m_ps- GetScriptState(&ss)))     return;     if (ss == SCRIPTSTATE_CONNECTED) {m_pScHost- m_ps-SetScr iptState(SCRIPTS TATE_DISCONNECTED);     GetDlgItem(IDC_RUNSCRIPT)-SetWindowText("Run Script");     } else {     m_pScHost- m_ps- SetScriptState(SCRIPTSTATE_CONNECTED);     GetDlgItem(IDC_RUNSCRIPT)- SetWindowText("Stop Script");     }     }     }     OnRunscript函数比较简单,它调用引擎的IActiveScript接口的G etScriptState成员函数获取当前引擎的状态,如果当前引擎中脚本正 在运行,则调用SetScriptState成员函数使引擎停止运行,引擎进入非 运行状态,并设置"Run Script"按钮的标题变为"Run Scr ipt";如果 当前引擎中脚本不在运行,则调用SetScriptState成员函数使引擎进 入运行状态,并设置"Run Script"按钮的标题变为"Stop Script"。     (8)编译并连接例程序。     至此我们已经完成了例程序的创建工作,接下来我们再写一个脚 本文件用来测试例程序是否能正确运行脚本文件。脚本文件中的代码 分两部分,一部分是全局的执行代码,当引擎首次被启动时,这部分代 码就开始运行;另一部分是事件响应函数,当日历控制产生事件时,脚 本代码中的事件响应函数就会被执行。为了测试例程序的正确性,我 们使用了下面的脚本代码。     ' Golobal code     MSGBOX("Global!")     '---------------------------------------------     Sub control_DblClick()     control.Nextyear     MSGBOX("You have double-clicked!")     End Sub     '----------------------------------------------     上述脚本代码并不进行实际的操作,只是弹出一个消息框表明脚 本代码获得了控制。     因为我们在例程序的CScriptDlg::OnLoadscript函数中指定了应 用受控对象名字为"control",所以在脚本代码中的control_DblClick 函数即指响应"control"对象的"DblC lick"事件,在函数control_Dbl Click中,调用了control对象方法Nextyear使当前日历后翻一年。并 弹出消息框以示脚本代码被执行了。     程序执行过程中,对事件响应后的情况如图4所示。图4 例程序响 应双击事件后的运行结果     如果我们单击"Stop Script"按钮停止脚本的执行,则再双击日历 控制,脚本代码中的事件响应函数不会被执行;如果用户再单击"Run S cript"按钮,则事件响应函数会再次被执行。如果用户希望执行其他 的脚本文件,则可以单击"Load Script"按钮,重新装入脚本文件。从 这里我们可以看出,应用程序对脚本引擎的控制是非常灵活的。读者 可以试一试。     五、结束语     Active Scripting技术是近几年发展起来的新技术,它对于软件 的性能扩展有重要的意义。从本文以上几节的介绍可以看出,在应用 系统中提供脚本语言的支持并不困难,甚至非常简单,因此,这种技术 有着广泛的发展前景,而且我们也已经看到越来越多的应用系统提供 了脚本语言的支持。     本文旨在对脚本技术作一个基本的介绍,希望文中所讲述的内容 能帮助读者在工作中用好这种技术。
    最新回复(0)