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