JScript supports SafeArrays of Variants only!!!

Recently I investigated a bug in Jscript which was reported on Vista. The scenario was working perfectly fine on XP and win2k3 but regressed in Vista. Here is the repro code...

var strSCID = "{305CA226-D286-468e-B848-2B2E8E697B74} 2";
var shell = new ActiveXObject("Shell.Application");
var cpls = shell.Namespace(3).Items(); // 3 is the ID for Control Panel
var num = cpls.Count;
while (num)
{
var fldrItem = cpls.Item(num-1);
WScript.Echo("The cpl " + fldrItem.Name + " belongs to category id " + fldrItem.ExtendedProperty(strSCID));
num--;
}

The issue was that above JScript code was printing nothing for fldrItem.ExtendedProperty(strSCID) on Vista. Same script was printing correctly on XP/Win2k3. On Debugging I found out that fldrItem.ExtendedProperty was returning a SafeArray on vista while it used to return a variant of type VT_BSTR or VT_I4 on XP/Win2k3. That means it was ExtendedProperty() which actually changed the behavior and regressed the scenario. Job done!

 But still I was wondering why JScript was not able to print the array because to my knowledge, JScript has got a datatype VBArray which is actually nothing but JScript representation of SafeArrays. I decided to debug more and go to the root of the issue. On debugging further I found out that Jscript can interpret SafeArrays only of Variants, i.e. vt of array variant must be set to VT_ARRAY | VT_VARIANT. On Vista ExtendedProperty() was returning SAFEARRAYS of type VT_ARRAY | VT_I4 and unfortunately Jscript doesn't recognizes these type of safearrays.

Well, you must be thinking that what do I mean JScript doesn't recognize one type of safearrays but not of other type. . What I mean is, if Jscript is passed a SafeArray of type other than VT_ARRAY | VT_VARIANT, then JScript just keeps the reference. None of the JScript operations which can be performed on a normal JScript VBArray Object, can be performed on these objects. JScript can be used to pass these non-variant safearrays from one automation object to another, but JScript itself can’t manipulate them. Hope it makes the thing clear.

 So if you are designing an Automation object (ActiveX object) and want that object to be consumed by JScript, then…

1. Design it in such a way that it neither takes nor returns a safearray.

2. Otherwise design it in such a way that it returns safearrays of type VT_ARRAY | VT_VARIANT (But doesn't take a safearray).

One important point to keep in mind is that SafeArray of type VT_ARRAY | VT_VARIANT can be converted to JScript representation of arrays but JScript arrays can’t be converted back to SafeArrays. This is just not supported at all. So while designing you ActiveXObject, keep in mind that if any of the methods needs a SafeArray as formal parameter than that method can’t be called from JScript.

 To know more about Jscript VBArrays please read Eric Lippert’s excellent blog.