Search code examples
c++vbscriptiactivescript

How to get a value from a VBScript to my C++ host?


I'm trying to execute a VBScript from a C++ ATL console application (non a VBS file, but simply a script embedded in my code) and get back a string from it.

I tried something like this:

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;

See also this question for how to set this up:

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

If I run this, VBScript complains about the non existant "WScript" object.

I tried replacing WScript.Echo with MsgBox and the code works fine (but of course doesn't give back the string).

I tried to use this:

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"

This writes my string to the console where the C++ app was launched, but don't return back the string to my code.

How do I get the value of s out of the Script into my Host process?

Just to clarify: I don't want to save the VBS, not the string to a temporary file.

The goal is to keep everything in memory without disk access.

I know I can leverage registry, but I'd like to avoid elevation. Don't know if some memory sharing is avalable to vbscript.

Other idea was named pipes, but I've no idea on how to share one between c++ and vbscript.


Solution

  • Just add a second call to ParseScriptText that evaluates your string variable as an expression.

    You have to pass SCRIPTTEXT_ISEXPRESSION as the dwFlags argument so that the scripting engine knows that you want to get the value of an expression.

    That is also in the official documentation for ParseScriptText:

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

    I tested it in Delphi and it works like a charm:

    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;