Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

three probably simple JS <--> C++ questions

131 views
Skip to first unread message

Grant Gayed

unread,
Nov 13, 2008, 4:21:56 PM11/13/08
to
Hi everyone,

I successfully have JS calling to a registered XPCOM component (C++) via
XPConnect. However the interface that's currently between them is not ideal
for what I'm try to do, so I'm hoping that I'm just missing some features of
xpidl. Basically I want JS to be able to invoke one method on my XPCOM
component with any number of arguments, each with any primitive type.
Currently on the JS side I have this working with:

"
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

var array =
Components.classes["@mozilla.org/array;1"].createInstance(Components.interfa
ces.nsIMutableArray);

var b =
Components.classes["@mozilla.org/supports-PRUint32;1"].createInstance(Compon
ents.interfaces.nsISupportsPRUint32);
b.data = 3;
array.appendElement(b, false);

var c =
Components.classes["@mozilla.org/supports-PRUint32;1"].createInstance(Compon
ents.interfaces.nsISupportsPRUint32);
c.data = 4;
array.appendElement(c, false);

var connect =
Components.classes['@eclipse.org/connect;1'].createInstance(Components.inter
faces.Connect);
var result = connect.callJava(array);
"

However ideally I wish the last line could just be made to look like:
"
var result = connect.callJava(3,4);
"

So my questions are:

1. Is there any way in xpidl to specify a method with a variable-length
argument list? If so then I'd like to do this instead of using the nsIArray
above.

2. Is there any way in xpidl to specify an argument to be of type "any
primitive type"? If so then I'd like to get rid of the nsISupports*
wrappers above.

3. (Unrelated to XPIDL) Is there any way to not show the Internet Security
dialog ("A script from "file://" is requesting enhanced abilities...") when
the top "UniversalXPConnect" line is executed (other than having the user
change the values in the about:config preferences)?

Thanks in advance for your help!
Grant


Arivald

unread,
Nov 14, 2008, 3:34:39 AM11/14/08
to
Grant Gayed pisze:
> netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

This is needed if you execute JS from Web page, and you want more
privileges. JS in XUL by default have all privileges (AFAIK).

>
> var array =
> Components.classes["@mozilla.org/array;1"].createInstance(Components.interfa
> ces.nsIMutableArray);
>
> var b =
> Components.classes["@mozilla.org/supports-PRUint32;1"].createInstance(Compon
> ents.interfaces.nsISupportsPRUint32);
> b.data = 3;
> array.appendElement(b, false);
>
> var c =
> Components.classes["@mozilla.org/supports-PRUint32;1"].createInstance(Compon
> ents.interfaces.nsISupportsPRUint32);
> c.data = 4;
> array.appendElement(c, false);
>
> var connect =
> Components.classes['@eclipse.org/connect;1'].createInstance(Components.inter
> faces.Connect);
> var result = connect.callJava(array);
> "
>
> However ideally I wish the last line could just be made to look like:
> "
> var result = connect.callJava(3,4);

How about this:

1) Write pure JS service component, which will do transformation between
JS types and C++ types? Pure JS component, used only from JS side can
implement only nsISupports, and from JS you use only "wrappedJSObject"
to access JS object.

For example, service Can have function array(), which gets JS array as
param, and return correctly initialized nsIArray.

so code may look:

var converter = Components.classes['@eclipse.org/typeConverter;1']
.getService().wrappedJSObject;

var result = connect.callJava(converter.array([2,4]));


Using service has benefit: typeConverter object is created once, when it
is first time needed.

>
> So my questions are:
>
> 1. Is there any way in xpidl to specify a method with a variable-length
> argument list? If so then I'd like to do this instead of using the nsIArray
> above.

Check function formatStringFromName() from nsIStringBundle. It gets
variable number of params.

URL to Mozilla MXR:
http://mxr.mozilla.org/seamonkey/source/intl/strres/public/nsIStringBundle.idl#74

and implementation:
http://mxr.mozilla.org/seamonkey/source/intl/strres/src/nsStringBundle.cpp#212

example how to use it from C++:
http://mxr.mozilla.org/seamonkey/source/intl/strres/src/nsStringBundle.cpp#209

From JS, you can use it this way:
bundle.formatStringFromName('format string', [param1, param2], 2);

or if you already have JS array:
bundle.formatStringFromName('format string', array, array.length);


>
> 3. (Unrelated to XPIDL) Is there any way to not show the Internet Security
> dialog ("A script from "file://" is requesting enhanced abilities...") when
> the top "UniversalXPConnect" line is executed (other than having the user
> change the values in the about:config preferences)?

Check this:
http://www.csie.ntu.edu.tw/~piaip/docs/CreateMozApp/mozilla-chp-12-sect-6.html

--
Arivald

Neil

unread,
Nov 14, 2008, 5:18:36 AM11/14/08
to
Grant Gayed wrote:

>Basically I want JS to be able to invoke one method on my XPCOM component with any number of arguments, each with any primitive type.
>

I think window.open does this by getting the native call context from
XPConnect and grovelling for the arguments there.

>Is there any way to not show the Internet Security dialog
>

You can register your component as a global object and implement the
security checked component interface (but this will mean that any web
page will be able to call your component).

--
Warning: May contain traces of nuts.

Neil

unread,
Nov 14, 2008, 5:19:17 AM11/14/08
to
Grant Gayed wrote:

>Is there any way in xpidl to specify an argument to be of type "any primitive type"?
>

nsIVariant

Grant Gayed

unread,
Nov 17, 2008, 2:35:18 PM11/17/08
to
Hi Arivald and Neil,

Thank-you for your quick answers! I have an implementation working based on
your suggestions, but now have a follow-up question regarding nsIVariant.

It seems like I should be able to specify my function in xpidl as
"nsIVariant callJava(in nsIVariant arg0)", where arg0 can be a JS array if
multiple args are to be passed. If I test this with an arg0 value of an
int, a string, etc., then this works fine on my C++ side (well, actually
Java side pretending to be C++). However if arg0 is a JS array, like [2],
then the nsIVariant.GetAsArray(...) call on the C++ side always fails with
NS_ERROR_CANNOT_CONVERT_DATA. I notice in nsIVariant.h that this method is
marked with "[notxpcom]". I'm not sure what this implies. Can it not be
used in the context I'm trying to use it in, or is it unrelated? As I said,
my "C++ side" is actually implemented in Java, so I can't step into the
GetAsArray(...) call to see why it's failing.

Grant


"Neil" <ne...@parkwaycc.co.uk> wrote in message
news:Q72dnW0vDpA7zYDU...@mozilla.org...

Arivald

unread,
Nov 18, 2008, 4:07:36 AM11/18/08
to
Grant Gayed pisze:
You should use Mozilla MXR to browse sources... It helps.
MXR is available at http://mxr.mozilla.org.


GetAsArray implementatuion:
http://mxr.mozilla.org/seamonkey/source/xpcom/ds/nsVariant.cpp#1231

1230 /* static */ nsresult
1231 nsVariant::ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type,
1232                           nsIID* iid, PRUint32 *count, void * *ptr)
1233 {
1238     if(data.mType == nsIDataType::VTYPE_ARRAY)
1239         return CloneArray(data.u.array.mArrayType, &data.u.array.mArrayInterfaceID,
1240                           data.u.array.mArrayCount, data.u.array.mArrayValue,
1241                           type, iid, count, ptr);
1242     return NS_ERROR_CANNOT_CONVERT_DATA;
1243 }

So I guess Variant you try to convert is not Array (its internal type is not nsIDataType::VTYPE_ARRAY).
You can verify type by calling
nsVariant::GetDataType(PRUint16 *aDataType)
I suspect JS array is not stored in nsIVariant as nsIDataType:VTYPE_ARRAY, but nsIDataType::VTYPE_INTERFACE, because VTYPE_ARRAY force all elements to be same type, while JS Array can contain any type. Proper getter function will be nsVariant::GetAsID(nsID *retval), where interface you query should be nsIArray.
When you get nsIArray, you should use its function to retrieve data.

--
Arivald



Grant Gayed

unread,
Nov 18, 2008, 12:08:41 PM11/18/08
to
To follow up, the problem was actually not mozilla-related, but was in our
invocation of the C++ GetAsArray(...) method from Java (our gen tool got
confused by its "NS_IMETHOD_(nsresult)" prefix, which I've now fixed).
GetAsArray(...) is now working and is passing the args through as an array
of nsIVariants.

Thanks again for your help!
Grant


"Arivald" <arivald_@AT_interia_DOT_pl> wrote in message
news:f7udnXdw5KMJGL_U...@mozilla.org...

0 new messages