如何从C ++中加载和调用VBScript函数?

当我们的产品发生特定操作时,我们有客户要求调用VBScript函数。 我一直在研究Windows脚本技术,但是我很难find我需要的东西。 希望你们有些人可以帮忙。

我们的产品是一个本地的C ++ Windows产品。 客户将指定一个我们将加载的VBScript文件,并且每当发生特定的事件时,我们都会在VBScript中调用一个特定的函数,并让它做它的事情。 我们可以在脚本的命名空间中提供对象,以便访问有关我们产品的信息。

我在MSDN上发现了关于IActiveScript接口的一些信息,以及一些相关的东西,但是找不到任何实例化实现这个VBScript接口的COM对象的例子。

我知道现在PowerShell可能是一个更好的select,但是我们的客户被困在很多遗留系统中,VBScript就是他们所知道的。

任何帮助,您可以提供(链接或其他),将不胜感激!

看看这个一些示例代码http://support.microsoft.com/kb/221992

有一个msscript.ocx可以帮助你,但如果你可以编写C ++可能比它的价值更麻烦http://msdn.microsoft.com/en-us/magazine/cc302278.aspx

我已经把一个“Hello World”IActiveScript C ++ ATL控制台应用程序放在一起:

  • 定义CSimpleScriptSite
    • IActiveScriptSiteIActiveScriptSiteWindow接口
    • 大多数函数的最小实现用虚存根实现
    • 没有错误处理。 请查阅MSDN IActiveScriptError 。
  • 使用CoCreateInstance一个新的IActiveSite对象
    • 创建VBScriptJScript实例
    • 使用IActiveSite::SetScriptSiteIActiveScriptSite链接到IActiveScriptSite
    • 调用QueryInterface获得一个IActiveScriptParse接口
    • 使用IActiveScriptParse执行VBScriptJScript代码
  • 例子:
    • JScript评估一个表达式
    • VBScript评估表达式
    • VBScript运行一个命令

码:

 #include "stdafx.h" #include <atlbase.h> #include <activscp.h> class CSimpleScriptSite : public IActiveScriptSite, public IActiveScriptSiteWindow { public: CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { } // IUnknown STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); // IActiveScriptSite STDMETHOD(GetLCID)(LCID *plcid){ *plcid = 0; return S_OK; } STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) { return TYPE_E_ELEMENTNOTFOUND; } STDMETHOD(GetDocVersionString)(BSTR *pbstrVersion) { *pbstrVersion = SysAllocString(L"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 *pIActiveScriptError) { return S_OK; } STDMETHOD(OnEnterScript)(void) { return S_OK; } STDMETHOD(OnLeaveScript)(void) { return S_OK; } // IActiveScriptSiteWindow STDMETHOD(GetWindow)(HWND *phWnd) { *phWnd = m_hWnd; return S_OK; } STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; } // Miscellaneous HRESULT SetWindow(HWND hWnd) { m_hWnd = hWnd; return S_OK; } public: LONG m_cRefCount; HWND m_hWnd; }; STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef() { return InterlockedIncrement(&m_cRefCount); } STDMETHODIMP_(ULONG) CSimpleScriptSite::Release() { if (!InterlockedDecrement(&m_cRefCount)) { delete this; return 0; } return m_cRefCount; } STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject) { if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow) { *ppvObject = (IActiveScriptSiteWindow *) this; AddRef(); return NOERROR; } if (riid == IID_IActiveScriptSite) { *ppvObject = (IActiveScriptSite *) this; AddRef(); return NOERROR; } return E_NOINTERFACE; } int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = S_OK; hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // Initialize CSimpleScriptSite* pScriptSite = new CSimpleScriptSite(); CComPtr<IActiveScript> spJScript; CComPtr<IActiveScriptParse> spJScriptParse; hr = spJScript.CoCreateInstance(OLESTR("JScript")); hr = spJScript->SetScriptSite(pScriptSite); hr = spJScript->QueryInterface(&spJScriptParse); hr = spJScriptParse->InitNew(); CComPtr<IActiveScript> spVBScript; CComPtr<IActiveScriptParse> spVBScriptParse; hr = spVBScript.CoCreateInstance(OLESTR("VBScript")); hr = spVBScript->SetScriptSite(pScriptSite); hr = spVBScript->QueryInterface(&spVBScriptParse); hr = spVBScriptParse->InitNew(); // Run some scripts CComVariant result; EXCEPINFO ei = { }; hr = spJScriptParse->ParseScriptText(OLESTR("(new Date()).getTime()"), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei); hr = spVBScriptParse->ParseScriptText(OLESTR("Now"), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei); hr = spVBScriptParse->ParseScriptText(OLESTR("MsgBox \"Hello World! The current time is: \" & Now"), NULL, NULL, NULL, 0, 0, 0, &result, &ei); // Cleanup spVBScriptParse = NULL; spVBScript = NULL; spJScriptParse = NULL; spJScript = NULL; pScriptSite->Release(); pScriptSite = NULL; ::CoUninitialize(); return 0; } 

IActiveScript和相关的接口工作得很好。 我在产品中使用它们与您所描述的完全相同。 一些外部客户编写自己的VBScript和JScript脚本来分析和更新应用程序数据,然后将其发布到数据库中。

使用CoCreateInstance()来实例化IActiveScript ,就像其他COM对象一样。 然后,您将调用其QueryInterface()方法来获取用于加载脚本代码片段的IActiveScriptParse接口,然后更新IActiveScript的状态以执行代码。

通过实现IDispatch派生类,然后使用IActiveScript::AddNamedItem()IActiveScriptSite::GetItemInfo()回调将它们传递给引擎,可以将自定义对象添加到脚本中。

在MSDN上有可用的IActiveScript使用示例。