【问题标题】:How to get a value from a VBScript to my C++ host?如何从 VBScript 获取值到我的 C++ 主机?
【发布时间】:2019-03-07 18:04:50
【问题描述】:

我正在尝试从 C++ ATL 控制台应用程序(非 VBS 文件,而只是嵌入在我的代码中的脚本)执行 VBScript 并从中获取字符串。

我尝试过这样的事情:

HRESULT hr = S_OK;
CComVariant result;
EXCEPINFO ei = { };

LPCOLESTR sCmd = L"s = \"something\"\r\n"
"WScript.Echo s\r\n";

hr = spVBScriptParse->ParseScriptText(sCmd, NULL, NULL, NULL, 0, 0, 0, &result, &ei);

std::cout << "got:" << result.cVal << std::endl;

另请参阅此问题以了解如何设置:

How to load & call a VBScript function from within C++?

如果我运行它,VBScript 会抱怨不存在的“WScript”对象。

我尝试用MsgBox 替换WScript.Echo 并且代码工作正常(但当然不会返回字符串)。

我试过用这个:

LPCOLESTR sCmd = L"s = \"something\"\r\n"
                  "Set fso = CreateObject (\"Scripting.FileSystemObject\")\r\n"
                  "Set stdout = fso.GetStandardStream (1)\r\n"
                  "stdout.WriteLine s\r\n"

这会将我的字符串写入启动 C++ 应用程序的控制台,但不要将字符串返回给我的代码。

如何从脚本中获取s 的值到我的主机进程中?

澄清一下:我不想将 VBS,而不是字符串保存到临时文件中。

我们的目标是在不访问磁盘的情况下将所有内容保存在内存中。

我知道我可以利用注册表,但我想避免提升。不知道一些内存共享是否适用于 vbscript。

其他想法是命名管道,但我不知道如何在 c++ 和 vbscript 之间共享一个。

【问题讨论】:

  • WScript 对象不是 VBScript 语言的一部分。当 WSH 托管脚本时,它由 Microsoft 的“Windows 脚本主机”注入。在这里,您的程序是新主机而不是 WSH,因此没有 WScript 对象。如果您想提供一个类似于 WScript 的宿主对象,您将不得不编写一个并从您的宿主程序中自己提供它(抱歉,我不知道 如何 是这样做的)
  • 这其实也不错。您可以将自己的对象从 C++ 公开到脚本环境中。这是通过IActiveScript::AddNamedItem() 等完成的。请在此处查看 Remys 答案:stackoverflow.com/a/7492025/426242

标签: c++ vbscript iactivescript


【解决方案1】:

只需向ParseScriptText 添加第二个调用,将您的字符串变量作为表达式进行计算。

您必须将SCRIPTTEXT_ISEXPRESSION 作为dwFlags 参数传递,以便脚本引擎知道您想要获取表达式的值。

这也在 ParseScriptText 的官方文档中:

https://docs.microsoft.com/en-us/scripting/winscript/reference/iactivescriptparse-parsescripttext

我测试了它in Delphi,它就像一个魅力:

procedure TestActiveScripting;
const
  SCRIPTTEXT_ISEXPRESSION = $00000020;
var
  hr: HResult;
  ScriptSite: IActiveScriptSite;
  VBScript: IActiveScript;
  VBScriptParse: IActiveScriptParse;
  res: Variant;
  ei: TExcepInfo;
begin
  // Initialize
  ScriptSite := TSimpleScriptSite.Create as IActiveScriptSite;

  hr := CoCreateInstance(CLSID_VBScript, nil, CLSCTX_INPROC_SERVER, IID_IActiveScript, VBScript);
  hr := VBScript.SetScriptSite(ScriptSite);
  VBScriptParse := VBScript as IActiveScriptParse;
  hr := VBScriptParse.InitNew;

  // Run some scripts
  hr := VBScriptParse.ParseScriptText('s = "something"', nil, nil, nil, 0, 0, 0, @res, ei);
  hr := VBScriptParse.ParseScriptText('s', nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @res, ei);
  ShowMessage(res);
end;

【讨论】:

  • 抱歉 Jens,没明白你的意思。如果你的意思是我已经有了“s”的值,我说这里的VBS代码只是为了测试目的。真正的 VBS 代码是一个巨大的脚本,由于不同的操作而产生一个字符串。最终目标是为庞大的 VBS 脚本代码库编写 C++ 包装器。
  • 仅将“s”作为脚本的最后一行,会引发 vbscript 语法错误。所以我试着把像 ss = s 这样的东西放进去。脚本成功完成,但我不确定是否没有返回值或者我无法取回它。我尝试使用 result.bstrVal,但显然指向空 BSTR。您能否详细说明“它将值作为最后一个表达式返回”的含义?
  • Jens:是的,关键是带有 SCRIPTTEXT_ISEXPRESSION 标志的第二次调用。在 C++ 中也像魅力一样工作。谢谢。马西莫。
  • 我已经删除了我的 cmets 并更新了答案以稍微清理一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2020-03-11
相关资源
最近更新 更多