Monday, August 13, 2007

JScript arrays and COM objects, part 1

In one of the projects I am doing I needed to create the COM object that is going to be used from JavaScript. It is a well-known scenario - the JScript implementations lets programmer instantiate any COM object that is an ActiveX automation-enabled, i.e. it implements an IDispatch interface. Then, you can call any method or manipulate any property of the COM object. It looks nice and perfect as long as you are using simple data types - numbers, string. Still, there is no problem even to pass the object. Your property may be even visible as an object to the script - you may pass back the pointer to the IDispatch implementation of some object as the property and it can be treated in script almost like a native JScript object.

However, it no longer looks so bright when you need to pass to/from your COM object an array. The problem is that what you call an array in JavaScript is the completely different thing than what you call an array in your programming language you use to create your COM object. To complicate things more, an array in JScript, an array in ActiveX world and an array in "serious" programming languages like C++ or Delphi are different objects. In C, C++ and pascal it is, simply, the segment of memory which contains consecutive elements of the same certain type. In ActiveX world and Visual Basic which is set in this world, array refers to what is called variant arrays, safe arrays or VBArrays, which are bound inside the VARIANT type and are still, more or less, block of memory. On the other hand, in JScript, the array is the object that has its own properties (in fact one - length) and methods. It is not hard to guess that it is in no way compatible with safe arrays.

Your COM object will use safe arrays as it is a standard way in ActiveX. Let us, firstly, concentrate on returning arrays from the function. We will consider the object Some.Object that exposes the following method:

[id(0x000002C0)]
HRESULT GetSomeArray([out, retval] VARIANT *retArr );
which may have the following implementation in Delphi:
function TSomeObject.GetSomeArray : OleVariant;
var
vals: array [0..2] of Variant;
begin
vals[0] := 'Hello';
vals[1] := 'World';
vals[2] := 'Dude';
Result := VarArrayOf(vals);
end;
In VBScript there would be no problem with dealing with the result of this function. In JScript, however, we get something which is not familiar - it is not an array as JScript understands it.
Is there any way to convert safe arrays to JScript arrays? Fortunately, the answer is affirmative. JScript architects has provided the class VBArray which is the JScript front-end to safe arrays. We can manage it in the following way:
var someObj = new ActiveXObject("Some.Object");
var arr = (new VBArray(someObj.GetSomeArray())).toArray();

alert(arr[0]);
We have used here toArray() method to convert the VBArray to the JScript array. We could also use getItem() method to directly access element of the array. Note, that script engines, both JScript and VBScript have the limitation - they can only process safe array containing elements of type Variant. Therefore, even if you want to pass an array of strings, make the array's element to be of type Variant.

OK, it was not so bad. But, what about passing an array to the function. Here, we encounter the real problem. We will solve it in the next post.

2 comments:

Anonymous said...

Great! You cured my headache by pointing out that the elements types in safearray should be VARIANT. Thanks

Anonymous said...

Thank you!
I've solved my problem!

There were visits to this blog since 20.08.2007.