Extending JScript
by Paul Butcher


Example 1:

var x = new Complex(1, 2);
var y = new Complex(3, 4);
var z = x.add(y);
messageBox(z.toString());

Example 2:

IDispatch* pdisp;
HRESULT hr = m_pfnCreateObject(pdp, &pdisp);
if(SUCCEEDED(hr))
{
    pvarRes->vt = VT_DISPATCH;
    pvarRes->pdispVal = pdisp;
}

Example 3:

(a)
person.salary = 25;
person["salary"] = 25;

(b)
forenames["2"] = "Fred";
forenames[2] = "Fred";
forenames[1 + 1] = "Fred";

Example 4:

var x = new Array(); // x.length == 0
x[2] = 42;           // x.length == 3
x[4] = 12;           // x.length == 5
x.length = 2;        // truncates the array

Example 5:
(a)
var unitx = new Vector(1, 0, 0);
var unity = new Vector(0, 1, 0);
var unitz = unitx.cross(unity);
messageBox(unitz.toString());

(b)
var vec = new Vector();
vec[0] = 0.2;
vec[2] = 0.3;
messageBox(vec.toString());

Example 6:

for(int i = 0; i < wcslen(rgszNames[0]); i++)
{
	if(!iswdigit(rgszNames[0][i]))
	{
		return DISP_E_MEMBERNOTFOUND;
	}
}
rgdispid[0] = _wtoi(rgszNames[0]) + DISPID_ARRAY;

Example 7:
if(dispidMember >= DISPID_ARRAY)
{
	int nIndex = dispidMember - DISPID_ARRAY;
	if(wFlags & DISPATCH_PROPERTYPUT)
	{
		if(pdispparams->cArgs != 1)
		{
			DISP_E_BADPARAMCOUNT;
		}
		return ArrayPut(nIndex,
            pdispparams->rgvarg[0]);
	}
	if(wFlags & DISPATCH_PROPERTYGET)
	{
		if(pdispparams->cArgs != 0)
		{
			return DISP_E_BADPARAMCOUNT;
		}
		return ArrayGet(nIndex, pvarResult);
	}
   return DISP_E_MEMBERNOTFOUND;
}



Listing One
class CScriptEngine :
    public CComObjectRootEx<CComMultiThreadModelNoCS>,
    public IActiveScriptSite
{
    public:
        CScriptEngine();
        virtual ~CScriptEngine();
        enum EngineType { EngineType_JScript, EngineType_VBScript };
        HRESULT Create(EngineType type);
        HRESULT Close();
        HRESULT ParseScript(const OLECHAR* pszScriptText);
        HRESULT AddGlobals(IDispatch* pDispatch);
        ...
};

Listing Two
[
    object,
    uuid(FCC9CDD3-EFFF-11d1-A9F0-00A0244AC403),
    dual
]
interface IComplex : IDispatch
{
    [propget, id(1)] HRESULT r([out, retval] double* pVal);
    [propput, id(1)] HRESULT r([in] double Val);
    [propget, id(2)] HRESULT i([out, retval] double* pVal);
    [propput, id(2)] HRESULT i([in] double Val);
    [id(3)] HRESULT add([in] IDispatch* pArg, 
                                [out, retval] IDispatch** pRetVal);
    [id(4)] HRESULT multiply([in] IDispatch* pArg, 
                                [out, retval] IDispatch** pRetVal);
    [id(5)] HRESULT toString([out, retval] BSTR* pRetVal);
};

Listing Three
HRESULT STDMETHODCALLTYPE
CJScriptTypeConstructor::InvokeEx(/* [in] */ DISPID id,
                           /* [in] */ LCID /*lcid*/,
                           /* [in] */ WORD wFlags,
                           /* [in] */ DISPPARAMS* pdp,
                           /* [out] */ VARIANT * pvarRes,
                           /* [out] */ EXCEPINFO * /*pei*/,
                           /* [unique][in] */ IServiceProvider* /*pspCaller*/)
{
    // We only know how to handle DISPID_VALUE
    if(id != DISPID_VALUE)
    {
        _ASSERT(false);
        return DISP_E_MEMBERNOTFOUND;
    }
    // This had better be a call to a constructor!
    if(!(wFlags & DISPATCH_CONSTRUCT))
    {
        _ASSERT(false);
        return DISP_E_MEMBERNOTFOUND;
    }
    // We don't know how to handle named arguments
    if(pdp->cNamedArgs != 0)
    {
        _ASSERT(false);
        return DISP_E_NONAMEDARGS;
    }
    // Construct an object and return its IDispatch pointer
    IDispatch* pdisp;
    HRESULT hr = m_pfnCreateObject(pdp, &pdisp);
    if(SUCCEEDED(hr))
    {
        pvarRes->vt = VT_DISPATCH;
        pvarRes->pdispVal = pdisp;
    }
    return hr;
}

Listing Four
HRESULT
CComplex::Create(DISPPARAMS* pdp, IDispatch** ppdisp)
{
    // Create the object
    CComObject<CComplex>* pNewObject = new CComObject<CComplex>;

    if(pdp->cArgs == 0)
    {
        // No arguments - initialize to default (zero)
        pNewObject->m_r = pNewObject->m_i = 0.0;
    }
    else if(pdp->cArgs == 2)
    {
        // Two arguments - first argument is r, second is i (remember that
        // the DISPPARAMS::rgvarg array contains arguments in reverse order)
        VARIANTARG vaTemp;
        VariantInit(&vaTemp);

        HRESULT hr = VariantChangeType(&vaTemp, &(pdp->rgvarg[0]), 0, VT_R8);
        if(!SUCCEEDED(hr))
        {
            return hr;
        }
        pNewObject->m_i = vaTemp.dblVal;

        hr = VariantChangeType(&vaTemp, &(pdp->rgvarg[1]), 0, VT_R8);
        if(!SUCCEEDED(hr))
        {
            return hr;
        }
        pNewObject->m_r = vaTemp.dblVal;
    }
    else
    {
        // Number of arguments must be 0 or 2
        return DISP_E_BADPARAMCOUNT;
    }
    pNewObject->AddRef();
    *ppdisp = pNewObject;
    return S_OK;
}

Listing Five
HRESULT
CComplex::DispatchToComplex(IDispatch* pdisp,CComObject<CComplex>** ppComplex)
{
  // Given an IDispatch*, convert it (if possible) to a CComObject<CComplex>*
  IComplex* pinterface;
  if(FAILED(pdisp->QueryInterface(IID_IComplex,
        reinterpret_cast<void**>(&pinterface))))
  {
        return DISP_E_TYPEMISMATCH;
  }
  *ppComplex = static_cast<CComObject<CComplex>*>(pinterface);
  pinterface->Release();
 return S_OK;
}

Listing Six
    [
        object,
        uuid(FCC9CDD4-EFFF-11d1-A9F0-00A0244AC403),
        dual
    ]
    interface IVector : IDispatch
    {
        [id(1)] HRESULT add([in] IDispatch* pArg, 
                                  [out, retval] IDispatch** pRetVal);
        [id(2)] HRESULT cross([in] IDispatch* pArg,
                                  [out, retval] IDispatch** pRetVal);
        [id(3)] HRESULT toString([out, retval] BSTR* pRetVal);
    };


6


