您可以添加 MFC 应用程序开销很小,使用 Microsoft ActiveX 脚本技术类似于 VBA 的脚本编写功能。 本文演示如何创建新的 MFC 应用程序中,或修改现有,合并了 VBScript 的支持。
|
更多信息
请按照以下步骤来生成并运行该示例: 基本工作流如下所示:
- 创建新 MFC 对话框基于的应用程序,或使用要添加脚本的支持已有的应用程序。
- 向对话框,添加一个编辑框和按钮,启用"需要返回"和"多行"编辑框中的属性中的样式。
- 使用成员变量选项卡下类向导 (CTRL-W),IDC_EDIT1 相关联的类型名为 m_edit1 的 CEdit 成员变量。
- 类向导用于创建一个名为 MyScriptObject,来自 CCmdTarget,与支持自动化的新类。如果您看到一个 ODL 文件有关的警告,请单击确定。
- 类向导的自动化选项卡上,在下选择 MyScriptObject,,并添加下面的方法:long gcd(long a, long b);void HelpAbout() ;void ShowValue (LPCTSTR 提示,长时间 n) ;
- 实现 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); }
- 打开 MyScriptObject.h,并移动虚拟析构函数 ~ MyScriptObject 类的受保护的分区中的公共部分。
- 双击对话框按钮来创建一个处理程序函数,并实现它,如下所示:
// 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();
- 打开您 [projectname]Dlg.h 文件并将下面的成员变量添加到您的类的公共部分:
MyScriptObject m_myScriptObject; IActiveScript *m_iActiveScript; IActiveScriptParse *m_iActiveScriptParse;
- 也在 [projectname]Dlg.h,添加下面的 #include 语句,您的类声明之前:
// Include ActiveX Script definitions... #include
// Include definition for MyScriptObject... #include "MyScriptObject.h" - 将以下代码添加到您 [只是之前的按钮处理程序实现,在 projectname]Dlg.cpp 文件:
// Your IActiveScriptSite implementation...class MyActiveScriptSite : public IActiveScriptSite {private: ULONG m_dwRef; // Reference countpublic: 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
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); }} - 编译并运行。
dim x dim y dim z x = 101*199 y = 313*199 z = gcd(x, y) ShowValue "gcd(" & x & ", " & y & ") = ", z HelpAbout
- 首先,VBScript 引擎,vbscript.dll,并获得 IActiveScript 和 IActiveScriptParse 接口。
- 您授予的 VBScript 引擎 IActiveScriptSite,引擎使用更高版本来获取,然后对您的对象调用的实现。
- 您添加的对象的实现,并希望对脚本可通过调用 IActiveScript::AddNamedItem()。
- 您提供的脚本文本通过 IActiveScriptParse::ParseScriptText() 执行。请注意这实际上还不是在运行该脚本。
- 脚本引擎将立即连接到您的 IActiveScriptSite::GetItemInfo() 无法识别,若要获取的接口指针的任何对象。
- IActiveScript::SetScriptState() 与 SCRIPT_STATE_CONNECTED 以运行该脚本,则调用。
- VBScript 引擎分析为您的脚本中的文本,以及当它遇到的方法调用或属性的引用时,它委托给您提供的接口的实现。
<linker : >
<linker : exmaple code : >