windows 如何从 C++ 中加载和调用 VBScript 函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7491868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to load & call a VBScript function from within C++?
提问by tyrel
We have customers asking for VBScript functions to be called when particular actions occur within our product. I've been trying to research the Windows Scripting technologies but I'm having difficulty finding exactly what I need. Hopefully some of you can help.
我们有客户要求在我们的产品中发生特定操作时调用 VBScript 函数。我一直在尝试研究 Windows 脚本技术,但我很难找到我真正需要的东西。希望你们中的一些人可以提供帮助。
Our product is a native C++ Windows product. The customer would specify a VBScript file, which we would load, and whenever a particular event occurs, we'd call a particular function in the VBScript and let it do its thing. We may provide objects within the script's namespace for it to access information about our product as well.
我们的产品是原生的 C++ Windows 产品。客户将指定一个 VBScript 文件,我们将加载该文件,并且每当发生特定事件时,我们将调用 VBScript 中的特定函数并让它执行其操作。我们可能会在脚本的命名空间中提供对象,以便它也可以访问有关我们产品的信息。
I found some information on MSDN about the IActiveScript interface, and some related things, but cannot find any examples of instantiating a COM object that implements this interface for VBScript.
我在 MSDN 上找到了一些关于 IActiveScript 接口的信息,以及一些相关的东西,但找不到任何实例化为 VBScript 实现这个接口的 COM 对象的例子。
I know that PowerShell would probably be a better option for this these days, but our customers are stuck in a lot of legacy systems and VBScript is what they know.
我知道现在 PowerShell 可能是一个更好的选择,但我们的客户被困在许多遗留系统中,而 VBScript 就是他们所知道的。
Any help you can provide (links or otherwise) would be appreciated!
您可以提供的任何帮助(链接或其他方式)将不胜感激!
回答by Stephen Quan
I've put together a "Hello World" IActiveScript C++ ATL console application that:
我已经组合了一个“Hello World”IActiveScript C++ ATL 控制台应用程序:
- Define
CSimpleScriptSite
class- Implement
IActiveScriptSite
interface (mandatory) - Implement
IActiveScriptSiteWindow
interface (optional) - Minimum implementation with most functions implemented with a dummy stub
- Has no error handling. Consult MSDN IActiveScriptError.
- Implement
- Use
CoCreateInstance
a newIActiveSite
object- Create instances of both
VBScript
andJScript
- Link the
IActiveSite
toIActiveScriptSite
usingIActiveSite::SetScriptSite
- Call
QueryInterface
to get anIActiveScriptParse
interface - Use
IActiveScriptParse
to executeVBScript
orJScript
code
- Create instances of both
- The sample:
- Evaluates an expression in
JScript
- Evaluates an expression in
VBScript
- Runs a command in
VBScript
- Evaluates an expression in
- 定义
CSimpleScriptSite
类- 实现
IActiveScriptSite
接口(必填) - 实现
IActiveScriptSiteWindow
接口(可选) - 使用虚拟存根实现的大多数功能的最小实现
- 没有错误处理。请参阅MSDN IActiveScriptError。
- 实现
- 使用
CoCreateInstance
新IActiveSite
对象- 同时创建的实例
VBScript
和JScript
- 链接
IActiveSite
到IActiveScriptSite
使用IActiveSite::SetScriptSite
- 调用
QueryInterface
获取IActiveScriptParse
接口 - 使用
IActiveScriptParse
执行VBScript
或JScript
代码
- 同时创建的实例
- 样品:
- 计算表达式
JScript
- 计算表达式
VBScript
- 运行命令
VBScript
- 计算表达式
Code:
代码:
#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;
}
A version of the above code can be found here:
可以在此处找到上述代码的一个版本:
回答by Remy Lebeau
IActiveScript
and related interfaces work very well. I use them in my product exactly the same way you have described. Some of out customers write their own VBScript and JScript scripts to analyze and update application data before it gets posted to a database.
IActiveScript
和相关的接口工作得很好。我在我的产品中使用它们的方式与您描述的完全相同。一些外部客户编写自己的 VBScript 和 JScript 脚本,以便在应用程序数据发布到数据库之前对其进行分析和更新。
You use CoCreateInstance()
to instantiate IActiveScript
, like you would any other COM object. You would then call its QueryInterface()
method to obtain an IActiveScriptParse
interface for loading snippets of scripting code, and then you update the IActiveScript
's state to execute the code.
您CoCreateInstance()
用来实例化IActiveScript
,就像您对任何其他 COM 对象一样。然后,您将调用其QueryInterface()
方法来获取IActiveScriptParse
用于加载脚本代码片段的接口,然后更新IActiveScript
的状态以执行代码。
You can add custom objects to the script by implementing IDispatch
-derived classes and then passing them to the engine using IActiveScript::AddNamedItem()
and an IActiveScriptSite::GetItemInfo()
callback.
您可以通过实现IDispatch
派生类将自定义对象添加到脚本中,然后使用IActiveScript::AddNamedItem()
和IActiveScriptSite::GetItemInfo()
回调将它们传递给引擎。
There are examples of IActiveScript
usage available on MSDN.
IActiveScript
MSDN 上有可用的用法示例。