First the code (careful of line wrapping that the email/news systems might impose)...

<html>
<body>
<script>

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

const nsISupportsArray = Components.interfaces.nsISupportsArray;

var x = Components.classes["@mozilla.org/supports-array;1"].createInstance(nsISupportsArray);

var y = new Object();
y.foo = "Hello XPConnect!";

// 1) do this...
y.wrappedJSObject = y;

x.AppendElement(y);

//NOW I WANT TO GET MY OBJECT BACK!!!

var z = x.GetElementAt(0);

// 2) and this...
// (which does more xpconnect magic than you might think)
z = z.wrappedJSObject;

alert(z);
alert(z.foo);

</script>
</body>
</html>

I think a few things need to be said...

I don't know what you are trying to build. But, you need to understand that direct use of xpcom from JS code is not appropriate for regular web content. Anything that needs the "UniversalXPConnect" privilege would require the user to trust your code completely. This gives the code the power to do anything from erasing files to sending arbitrary files off to the net. This is just not the sort of power that one wants to grant to downloaded web content. If you are extending mozilla or building an intranet application or something like that, then that's a different story.

That said, the thing I think you are missing is that the JS object system and the xpcom object system are completely different and know nothing about each other. XPConnect exists to be a bridge between those two object systems. The nsISupportsArray you are constructing is implemented in C++ and works with xpcom objects. The pattern of the code is exactly what I was describing before. Whether you are implementing the native component or not is immaterial.

This is not about 'casting'. XPCOM is about interfaces based on C++ object vtbls. JSObjects are dynamic and happen to be implemented using C. They have no fixed interfaces or C++ vtbls. XPConnect is all about building *additional objects*: wrappers. XPConnect builds one kind of wrapper object around xpcom objects that is used to expose the object to JS so that an xpcom object *looks* like a JSObject. And, xpconnect builds another kind of wrapper object around JSObjects to expose to xpcom to make the JSObject look like an xpcom object.

There is quite a bit of this wrapping going on behind the scenes in the little example above.

The thing you seem to be expecting is that when you call GetElementAt on the xpcom nsISupportArray that the object you get back will be automatically unwrapped to be the self-same object that you passed in. Very early on in the history of xpconnect that is exactly what would have happened. But, as we started to build xpcom components in JS (and there are many of these in mozilla now), we discovered that this actually was a disadvantage. It made the JS use of components work differently depending on whether the given component was implemented in JS or C++. It exposed the guts of the component to arbitrary JS code - thus breaking the interface based encapsulation of xpcom. And, it kept various xpconnect utilities (like 'instanceof') from working on JS components the same way they work on C++ components (when accessed by JS code). We *wanted* JS xpcom components to work exactly like C++ xpcom components (or Python xpcom components for that matter). So, I implemented the scheme that we have now...

When you call AppendElement xpconnect builds a wrapper around your JSObject to make it look like an xpcom object. When you call GetElementAt xpconnect retrieves an xpcom object (which happens to be a wrapper) for you. And then xpconnect builds a wrapper around that wrapper to make the object look like a JSObject. In the xpconnect internals this is called 'double wrapping'. So, the object you get back is wrapped like any other xpcom object to only expose the xpcom interface that have been indicated.

In the *rare* case where one wants to retrieve an xpcom object and get at the underlying JSObject I supplied the 'wrappedJSObject' scheme shown in the example above.

Also note that it is wise to use exception handling as shown in my previous posting in order to safely catch cases where the object you are trying to unwrap might not actually be a wrapped JSObject as you expected.

I hope this clears things up for you - or at least shows you how to do what you are trying to do.

John.

Snider, Sean wrote:
Hmmmm. . . maybe I am not being clear enough. . no this example doesn't
really help me b/c I am not implementing the XPCom object that I am
handing a plain old JS Object too. . .
Let me try to explain this a little better, the code that I wrote before
Is code inside the web browser (not in an XPCom/XPConnect component).
In the browser I contruct an nsISupportsArray
const nsISupportsArray = Components.interfaces.nsISupportsArray;
var x = Components
.classes["@mozilla.org/supports-array;1"]
.createInstance(nsISupportsArray);

and the I construct an regular object.

var y = new Object();
y.sean = "snider";

Then I put this object in the first slot of the array.

x.AppendElement(y);

When I ask for the element back from the Array (x.GetElementAt(0)) in
browser script code, it just tells me that the object is an instance of
nsISupports, but the properties of the object that I inserted are no
longer defined (i.e. y.sean is now undefined!!!)!! The wrapping
methodolgy when in the context of browser script code (NOT XPCom
component code) doesn't seem to work, or at the very least I am doing it
wrong.

It's as if my object is either:

A.) Managled
B.) No longer of JS Object type
My guess is that b/c I am using the nsISupportsArray component, when I
do the insertion into the array, the object is either upcast to
nsISupports and now needs to be converted back, or its child members are
lost during insertion.

Basically the example you showed me is backwards from what I want. It
shows how to take in a JSObject from the browser script code (or XPCom
JS code for that matter) and deal with it.

Does this explain my problem better???? (Please refer to my previous
email to see my sample code again).


Sean Snider
Software Engineer I
[EMAIL PROTECTED]
-----Original Message-----
From: John Bandhauer [mailto:[EMAIL PROTECTED]] Sent: Saturday, December 14, 2002 7:50 PM
To: [EMAIL PROTECTED]
Subject: Re: PLEASE HELP, PLEASE PRETTY PLEASE

Snider, Sean wrote:

So then I had a look at:

http://lxr.mozilla.org/seamonkey/source/modules/plugin/samples/4x-script

able/script-test.html#17

FWIW, there used to be a couple more uses of wrappedJSObject. I know chatzilla used to use it. The example you looked at was something that Patrick Beard was fiddling with for scripting plugins. I don't know if he ever got it to do what he wanted.

The only remaining example that I think applies is:

http://lxr.mozilla.org/seamonkey/source/extensions/irc/js/lib/connection
-xpcom.js

John.





Reply via email to