Thanks for this code. It'll be really useful.

Ok. You can call me dumb or whatever you want, but I'm still working on
this

Yesterday, I finally could call the method of my component instanced in
javascript (hoorray!). It has been hard for me (well, i first heard
about XPCOM at the beginning of october), but I'm getting into it.

My simple component is done in javascript, but to implement the
functionality i need it in c++ so i'll start using your code to begin
the 'translation'.

At last I also needed to implement nsISecurityCheckedComponent to make
it work (not only nsIClassInfo).

I promise i'll write a tutorial-for-dumbs as soon as I make it work in
c++, containing both javascript and c++ implementations, but I'll need
some time. Please, be patient.

Regards.

timeless ha escrito:

> Mitchi wrote:
> > i was trying to understand it line to line.
>
> > But my problem is with the C++ version,
> > where things aren't as clear as in the sidebar implementation.
>
> your problem is trying to use the C++ version instead of finding the
> one to one mapping between JS and C++.
>
> Not every line in here is annotated, but almost all of them are obvious
> one to one mappings. Note that many lines in JS or C++ need an
> additional line in the other language. I might note that in some cases,
> in others, well.... if the line counts don't match, assume that one of
> them expanded :).
>
> it goes something like this:
>
> /* IDL file myIFoopy.idl */
> [scriptable]
> interface myIFoopy : nsISupports {
>   /* method
>    * @param foopy something to think about
>    *
>    * @return a randomish number based on howtever the implementation
> feels about foopy
>    */
>   long method(in AString foopy);
>   /* dohtem
>    * @param out ypoof something to get
>    * @bugs this should just be long dohtem() but that wouldn't demo
> outs in js.
>    *             as such, using this method in js is a royal pain
>    */
>   void dohtem(out long ypoof);
>   /* cupid is not readonly, it has both a setter and a getter.
>    * it stores a cupid.
>    * how cupid is used is entirely implementation specific.
>    */
>   attribute nsISupports cupid;
>   attribute nsISupports dipuc;
> }
>
>
> /* JS impl myFoopy.js */
> function myFoopy(){}
> myFoopy.prototype = {
>   /* this is the dirty definition approach, objects normally like to
> know who their
>    * constructor is, but we're destroying the object here, so it
> doesn't unless we
>    * store it by hand.
>    *
>    * this is xpcom private
>    */
>   constructor: myFoopy,
>   /*
>    * this is xpcom public if you QI to nsISupports (and everything
> derives from
>    * nsISupports, so you don't actually need to QI to it unless you
> have a tearoff
>    * which you could have in c++ [js is protected from that problem by
> xpconnect
>    * magic].
>    */
>   QueryInterface: function
>   /* what matters to xpcom is the public name before the colon.
>    * the name of the function is an internal name used by things like
> debuggers
>    * and profilers, and people who want to read and understand your
> code.
>    */
>   myFoopy_QueryInterface(iid) {
>     /* I refuse to use sugar: for each (i in this.interfaces)
>      * here because when someone pollutes Object.prototype or
> Array.prototype,
>      * the sugar breaks and people wonder why things stopped working.
>      * this happens often enough that the sugar is just dangerous.
>      * plus that sugar can't be converted to C++, and it is possible to
> write this sugar free
>      * version in C++, although it isn't recommended.
>      */
>     for (var i = 0; i < this.interfaces; ++i) {
>       if (iid.equals(this.interfaces[i]))
>         return this;
>       throw Components.results.NS_ERROR_NO_INTERFACE;
>     }
>   },
>   /* this is as close to table driven qi as js can get, and it's
> conveniently a first step
>    * to nsIClassInfo.
>    *
>    * this is xpcom private
>    */
>   interfaces: [
>     Components.interfaces.nsISupports,
>     Components.interfaces.myIFoopy
>   ],
>   /* storage for cupid
>    *
>    * this is xpcom private
>    */
>   _cupid: null,
>   /* myIFoopy.method
>    * note that the case for method here matches the case in the idl
> file.
>    *
>    * this is xpcom public if you QI to myIFoopy
>    */
>   method: function myFoopy_method(foopy) {
>     if (foopy.charAt(0) == "f" &&
>         foopy.charAt(1) == "o" &&
>         !foopy.charAt(2))
>       return 10;
>     if (foopy == 'of') {
>       /* it sucks, but this is how you get the result of an out value
> for an xpcom method.
>        * this is also why this.dohtem should be a long dohtem();
>        * instead of void dohtem(out long ypoof);
>        *
>        * first you need an object
>        */
>       var ypoof = {};
>       /* then you pass it to the C++; this feels so much like visual
> basic.... */
>       this.dohtem(ypoof);
>       /* then you grab the magically populated value from the object,
>        * that's your out-ed value.
>        */
>       return ypoof.value;
>     }
>     return 19;
>   },
>   /* myIFoopy.dohtem
>    * note that the case for method here matches the case in the idl
> file.
>    *
>    * this is xpcom public if you QI to myIFoopy
>    */
>   dohtem: function myFoopy_dohtem(foopy) {
>     foopy.value = 15;
>   },
>   /* getter myIFoopy.cupid
>    * this is written using syntactic sugar
>    * this is xpcom public if you QI to myIFoopy
>    */
>   get cupid() {
>     return this._cupid;
>   },
>   /* setter myIFoopy.cupid
>    * this is written using syntactic sugar
>    * this is xpcom public if you QI to myIFoopy
>    */
>   set cupid(cupid) {
>     this._cupid = cupid;
>     /* this is only in case someone calls our setter from js and it
> only makes sense */
>   },
>   /* getter myIFoopy.dipuc
>    * this is not written using syntactic sugar
>    * this is xpcom public if you QI to myIFoopy
>    */
>   getDipuc() {
>     return this.cupid;
>   },
>   /* setter myIFoopy.dipuc
>    * this is not written using syntactic sugar
>    * this is xpcom public if you QI to myIFoopy
>    */
>   setDipuc: function myFoopy_SetDipuc (cupid) {
>     /* the use of this. is here is required for js,
>      * and can be conveniently seen as related to the C++
>      * example if you pretend that this is an xpcom pointer instead of
> a native pointer
>      */
>     return this.cupid = cupid;
>   }
> }
>
> /* the implementation of nsIModule is already documented elsewhere and
> is beyond the scope of this mapping */
>
> /* C++ impl myFoopy.cpp */
>
> class myFoopy : public myIFoopy {
>   private:
>   /* constructor
>    *
>    * this is xpcom private
>    */
>   myFoopy();
>   /* storage for cupid
>    *
>    * this is xpcom private
>    */
>   nsCOMPtr<nsISupports> mCupid;
>   public:
>   NS_DECL_MYIFOOPY;
>   NS_DECL_ISUPPORTS;
> }
> myFoopy::myFoopy(){}
>
> /* note that you can only have one of these per class since they define
> the same methods
> /* this is the standard syntatic sugar approach */
> NS_IMPL_ISUPPORTS1(myFoopy, myIFoopy)
> /* end standard sugar */
>
> /* this is a more flexible slightly sugary approach */
> NS_IMPL_ADDREF(myFoopy)
> NS_IMPL_RELEASE(myFoopy)
> NS_INTERFACE_MAP_BEGIN(myFoopy)
>   NS_INTERFACE_MAP_ENTRY(nsISupports)
>   NS_INTERFACE_MAP_ENTRY(nsIFoopy)
> NS_INTERFACE_MAP_END(myFoopy)
> /* end rarer alternate sugary approach */
>
>   /*
>    * this is xpcom public if you QI to myIFoopy
>    */
> NS_IMETHODIMP
>   /* myIFoopy.method
>    * note the lack of any special prefix but that method is
> InitialCaps,
>    *   unlike the idl declaration.
>    */
> myFoopy::Method(/*in strings are a bit special*/ const nsAString
> &foopy, PRInt32 *aRetval) {
>     if (foopy.CharAt(0) == "f" &&
>         foopy.CharAt(1) == "o" &&
>         foopy.CharAt(2) == "") {
>       /* note that it takes two lines to express a return */
>       *aRetval = 10;
>       return NS_OK;
>     }
>     /* but this allows us to not use 'else', just as the js doesn't
> need it ... */
>     if (foopy.EqualsLiteral("of")) {
>       /* sometimes C++ is shorter ... */
>       Dohtem(aRetval);
>       return NS_OK;
>     }
>     *aRetval = 19;
>     return NS_OK;
>   }
> NS_IMETHODIMP
>   /* myIFoopy.dohtem
>    * note the lack of any special prefix but that method is
> InitialCaps,
>    *   unlike the idl declaration.
>    */
> myFoopy::Dohtem(PRInt32 *aYpoof) {
>     *aYpoof = 15;
>     return NS_OK;
>   }
>   /*
>    * this is xpcom public if you QI to myIFoopy
>    */
> NS_IMETHODIMP
>   /* getter myIFoopy.cupid
>    * note that Get is part of the name and both Get and Cupid are
> InitialCaps
>    * note the double pointer since we need to be able to pass out a
> pointer
>    */
> myFoopy::GetCupid(nsISupports **aResult) {
>     /* xpcom says we addref for getters... */
>     NS_IF_ADDREF(*aResult = mCupid);
>     return NS_OK;
>   }
>   /*
>    * this is xpcom public if you QI to myIFoopy
>    */
> NS_IMETHODIMP
>   /* setter myIFoopy.cupid
>    * note that Set is part of the name and both Set and Cupid are
> InitialCaps
>    * note the single pointer since we only need to be given a pointer
>    */
> myFoopy::SetCupid(nsISupports *aCupid) {
>     mCupid = aCupid;
>   }
>   /*
>    * this is xpcom public if you QI to myIFoopy
>    */
> NS_IMETHODIMP
>   /* getter myIFoopy.dipuc
>    * note that Get is part of the name and both Get and Dipuc are
> InitialCaps
>    * note the double pointer since we need to be able to pass out a
> pointer
>    */
> myFoopy::GetDipuc(nsISupports **aResult) {
>     /* xpcom says we addref for getters... */
>     /* but the code we're calling does that, so we just let it manage
> the reference
>      * since we aren't dropping it or holding it or otherwise
> influencing the one it
>      * returns.
>      */
>     return GetCupid(aResult);
>   }
>   /*
>    * this is xpcom public if you QI to myIFoopy
>    */
> NS_IMETHODIMP
>   /* setter myIFoopy.dipuc
>    * note that Set is part of the name and both Set and Dipuc are
> InitialCaps
>    * note the single pointer since we only need to be given a pointer
>    */
> myFoopy::SetDipuc(nsISupports *aCupid) {
>     /* the useless use of this-> is here for equivalence
>      * to the use of this. in js,
>      * and can be conveniently seen as related to the JS
>      * example if you pretend that this is an xpcom pointer to myIFoopy
>      * instead of a pointer to myFoopy.
>      */
>      * to the useless use of this. in the js example */
>     return this->SetCupid(aCupid);
>   }
>
>
> /* the implementation of nsIModule is already documented elsewhere and
> is beyond the scope of this mapping */
>
>
>
> /* XPCOM Exception handling (JavaScript) eh.js: */
> function eh_js() {
>   try {
>     xpcom_wrapped_object.method();
>   } catch (e) {
>     switch (e.result) {
>     case Components.results.NS_ERROR_FILE_UNRECOGNIZED_PATH:
>       doSomething();
>       return;
>     case Components.results.NS_ERROR_FILE_UNRESOLVABLE_SYMLINK:
>       throw Components.results.NS_ERROR_FILE_EXECUTION_FAILED;
>     case Components.results.NS_ERROR_FILE_UNKNOWN_TYPE:
>       throw e.result;
>     default:
>       doSomethingElse();
>       return;
>     }
>   }
> }
>
> /* XPCOM Exception handling (C++) eh.cpp: */
> nsresult Eh_js() {
>   /* this is equivalent to e.result */
>   nsresult rv;
>   /* this is the method call */
>   rv = xpcom_object->Method();
>   /* this is the catch block */
>   if (NS_FAILED(rv)) {
>     switch (rv) {
>     /* Components.results is a bad reflection of a limited set of
> nsresult values, in C++,
>      * you get as many as you include, in JS you need to do something
> like
>      * http://viper.haque.net/~timeless/nsError.js if you want things
> that aren't reflected.
>      */
>     case NS_ERROR_FILE_UNRECOGNIZED_PATH:
>       /* Assuming DoSomething is an XPCOM type method we need to catch
> its return value
>        * since in js that would automatically result in a throw.
>        */
>       rv = DoSomething();
>       /* if the return value from DoSomething() is NS_OK,
>        * then we're returning that non exceptional value
>        * otherwise we're returning the thrown exception.
>        */
>       return rv;
>     case NS_ERROR_FILE_UNRESOLVABLE_SYMLINK:
>       /* here we're throwing a different exception value, just as the
> js does */
>       return NS_ERROR_FILE_EXECUTION_FAILED:
>     case NS_ERROR_FILE_UNKNOWN_TYPE:
>       /* here we're rethrowing the same exception value we got, just as
> the js does */
>       return rv;
>     default:
>       /* this is equivalent to if (NS_FAILED(rv)) { DoSomethingElse() }
> which is what you would
>        * normally see in C++ code, but I've left it in a default just
> to show that you can make life
>        * complicated if you want to.
>        */
>       rv = DoSomethingElse();
>       return rv;
>     }
>    }
>   }
>   /* this is equivalent to any non throw in JS,
>    * which is the normal implicit return undefined at the end of the js
> function.
>    */
>   return NS_OK;
> }

_______________________________________________
dev-security mailing list
dev-security@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-security

Reply via email to