Tuesday, August 21, 2007

JScript arrays and COM objects, part 3

I have promised in my previous post that I will present also how to deal with JScript arrays in C++ code with ATL. Below, there is a code of a function, I have come up with, in C++ that gets the JScript array of integers and calculates the sum:

#include <string>
#include <sstream>
#define _C(oleop) hr = oleop; \
if (!SUCCEEDED(hr)) \
return hr;

STDMETHODIMP CHelloWorld::JSArrSum(VARIANT js_arr, LONG* Sum)
{
HRESULT hr;

/* checking if argument is an object */
if (!(js_arr.vt & VT_DISPATCH))
return E_INVALIDARG;

/* retrieving IDispatch */
IDispatch *disp = js_arr.pdispVal;
if (js_arr.vt & VT_BYREF)
disp = *(js_arr.ppdispVal);

/* getting array's length */
DISPPARAMS params;
FillMemory(¶ms, sizeof(DISPPARAMS), 0);
VARIANT res;

DISPID dl;
LPOLESTR ln = L"length";

_C(disp->GetIDsOfNames(IID_NULL, &ln, 1, LOCALE_USER_DEFAULT, &dl));

_C(disp->Invoke(dl, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
¶ms, &res, NULL, NULL));

VARIANT len1;
VariantInit(&len1);

_C(VariantChangeType(&len1, &res, 0, VT_I4));
LONG len = len1.lVal;

/* summing elements */

int total = 0;
for (int i = 0; i < len; i++)
{
std::stringstream ss;
ss << ind =" CComBSTR(ss.str().c_str());">GetIDsOfNames(IID_NULL, &ind, 1, LOCALE_USER_DEFAULT, &id));
_C(disp->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &res, NULL, NULL));

VARIANT val1;
VariantInit(&val1);

_C(VariantChangeType(&val1, &res, 0, VT_I4));
total += val1.lVal;
}

*Sum = total;

return S_OK;
}

What it does is simply the following:

  1. It is checked if an argument is some object (hopefully, a JScript array)
  2. IDispatch reference of an array is retrieved from the variant.
  3. The property length is obtained from the array's object as it is for any automation object. We receive some variant value, so we need to convert it to integer.
  4. For each element of an array its DISPID is queried and its value received, converted to integer, and summed up.
  5. It returns the sum of array's values.
It can be called from JScript as following:

var arr = new Array();
arr[0] = 10;
arr[1] = 15;
arr[2] = 2;

var obj = new ActiveXObject("ProgID.OfClass");
alert(obj.JSArrSum(arr));

12 comments:

Anonymous said...

I have developed a desktop gadget that utilizes an ActiveX object. I have no problem sending data to the ActiveX object. However, I see no way register callbacks from the object. Google's desktop javascript engine, seems lacking in this respect. Thoughts?

Krzysztof Olczyk said...

Yes, you are right. Javascript is not capable of sinking ActiveX events, nor are any routines to do so included in GD API. All you can do is to write your own ActiveX (hybrid) object where you hook events and forward it to JScript function.

Pedro Fraca said...

I have de reverser problem, return an Array to JavaScript. I'm trying with variant. Do you knwo any way?

Krzysztof Olczyk said...

Actually it's the same problem.
You need to return and IDispatch object which return array's element by pairt of GetIDsbyName and Invoke methods.

Pedro Fraca said...

Hi, I'm trying to implement your code and I have the next problem.

I publish the function to the javascript with this code.

DISP_FUNCTION( CSample1Ctrl, "showArray", showArray, VT_I2,VTS_VARIANT )

My JavaScript code is the next:

var c = new Array();
c.push(3);
c.push(3);
c.push(3);
c.push(3);
c.push(3);
alert(c.length);
alert(objJSExt.showArray(c));

And when I execute the next instruction the progam breaks

_C(disp->GetIDsOfNames(IID_NULL, &ln, 1, LOCALE_USER_DEFAULT, &dl));

Appears to the Array in javascript not is the expected dataype.

The JavaScript Code is:

var c = new Array();
c[0] = 3;
c[1] = 3;
c[2] = 3;
c[3] = 3;

alert(c.length);
alert(objJSExt.showArray(c));

Have you got any idea?

Pedro Fraca said...

How you publish the method???. Do you use the nex function?.
DISP_FUNCTION( CSample1Ctrl, "showArray", showArray, VT_I2,VTS_PVARIANT)

I think the problems is in the parameter that i export.

Thanks

Krzysztof Olczyk said...

Are you using ATL?

Pedro Fraca said...

I'm using MFC Active X control. I think the dataype may be the same. I try it with ATL. Thanks.

pdp said...

Unable to compile this line:

ss << ind =" CComBSTR(ss.str().c_str());">GetIDsOfNames(IID_NULL, &ind, 1, LOCALE_USER_DEFAULT, &id));

Will you please simplify it? What is the value of 'ind' here?

I am unable to break that line into simpler statements.

Anonymous said...

Hi,
Thanks for this post. I want to pass array from Javascript to C# component , is it possible ?

Echo said...

Thanks this is exactly what I was looking for.
Thanks again.

-Echo
http://www.echo.net84.net/

arya said...

thank you for the information is very helpful at all

There were visits to this blog since 20.08.2007.