2

I have an application that hosts the Active Script JScript engine. Depending on the version of jscript.dll, it runs up to JScript 5.8. The application exposes many objects and methods to the JScript environment.

When the script calls a certain function, with IDL like this:

HRESULT func(VARIANT varInput);

I want determine if the input is an instanceof another function (i.e., if the function is a constructor whose prototype is in the prototype chain of input). In JScript:

input instanceof Error

How can this be done in C++ with IDispatch/IDispatchEx?

The method has access to the IActiveScript (implemented by the JScript engine) and IActiveScriptSite (implemented by the host) interfaces, so it is possible to get the global object with IActiveScript::GetScriptDispatch, from which any other constructor (such as Error) can be retrieved.

3 Answers3

0

The IDispatch* you have wrapped into variant has a DISPID_VALUE (= 0) property, which in case of Error object would give you a string value "[object Error]".

You can also define or inject JScript functions like:

function IsInstanceOf(object, type) {
    return object instanceof type;
}
function IsInstanceOfError(object) {
    return IsInstanceOf(object, Error);
}

and call them back from your C++ code using IDispatch* you already hold to have JScript engine checked it against specific type and returned you true/false result of such check.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Thank you; however, I am looking for a method that does not require code injection. If code is added to the JScript engine, including if you call Function as a constructor with (IDispatchEx)::InvokeEx(DISPATCH_CONSTRUCT), the injected code will be visible in the debugger. If the injection happens repeatedly, your debugging space will be cluttered with many repetitions of the same code. I would like it so that there is no injection whatsoever, not even one. – Sean 'SeanTek' Leonard Sep 26 '12 at 11:17
0

I think Roman R's is a good answer, but, to minimize the code injection, you can use IActiveScriptParse::ParseScriptText to turn any anonymous JavaScript function into an IDispatch pointer:

    HRESULT hr = S_OK;
    EXCEPINFO ei = { };
    CComVariant vIsErrorFunc;
    hr = spIActiveScriptParse->ParseScriptText(
        OLESTR("(function () { return function (obj) { return obj instanceof Error; }; } )();"),    // pstrCode
        NULL,                       // pstrItemName
        NULL,                       // punkContent
        NULL,                       // pstrDelimiter
        0,                          // dwSourceContextCookie
        0,                          // ulStartingLineNumber
        SCRIPTTEXT_ISEXPRESSION,    // dwFlags
        &vIsErrorFunc,              // pvarResult
        &ei                         // pexcepinfo
        );

The anonymous function conveniently has a DISPID of DISPID_VALUE which you can fire using IDispatch::Invoke. If you have a JavaScript object in a VARIANT you can test it as follows:

// VARIANT* pvObject -- JavaScript object to test
DISPPARAMS dispParams = { pvObject, 0, 1, 0 };
CComVariant vResult;
hr = V_DISPATCH(&vIsErrorFunc)->Invoke(
    DISPID_VALUE,
    IID_NULL,
    0,
    DISPATCH_METHOD,
    &dispParams,
    &vResult,
    NULL,
    NULL);

You can persist vIsErrorFunc so that you can reuse the anonymous function repeatedly, or you can let it go out of scope and have it garbage collected. Either way, there ought to be no lasting impact to the client code in the JavaScript engine.

** EDIT: **

I found that my original anonymous function did not work (I got VT_EMPTY instead of VT_DISPATCH):

function (obj) { return obj instanceof Error; }

To trick it, I wrapped the function as follows:

(
    function ()
    {
        return function (obj) { return obj instanceof Error; }
    }
) ()

I hope this explains the weird expression in my example.

Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
-1

The C++ equivalent to Java's instanceof operator is to use dynamic_cast. e.g.,

x instanceof y

would be the following in C++:

dynamic_cast<y*>(x) != 0
Dave Doknjas
  • 6,394
  • 1
  • 15
  • 28