Creating Applications with Mozilla-Chapter 8. XPCOM- P3

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:16

0
34
lượt xem
6
download

Creating Applications with Mozilla-Chapter 8. XPCOM- P3

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'creating applications with mozilla-chapter 8. xpcom- p3', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:
Lưu

Nội dung Text: Creating Applications with Mozilla-Chapter 8. XPCOM- P3

  1. Chapter 8. XPCOM- P3 8.2.1.3. Implementing the required XPCOM methods in JavaScript Once the definitions in the nsISimple interface are implemented, you need to implement required methods and factories that make this JavaScript implementation class an XPCOM component. Recall that all XPCOM components must implement the nsISupports interface. Example 8-3 shows an implementation of QueryInterface specific to our new component. QueryInterface ensures that the correct interface (nsISimple) is used by matching the iid with the nsISimple interface that this component implements. If the interface doesn't match, then the argument is invalid. In this case, the exception Components.results.NS_ERROR_NO_INTERFACE is thrown, which maps to the error code number 2147500034, and code execution is stopped. If the interface identifier parameter matches the interface, then an instance of the implementation class object SimpleComponent with its interface is returned as a ready-to-use XPCOM component. In XPCOM, every component you implement must have a QueryInterface method. Example 8-3. QueryInterface method for nsISimple interface QueryInterface: function (iid) { if(!iid.equals(Components.interfaces.nsISimple) && !iid.equals(Components.interfaces.nsISupports))
  2. throw Components.results.NS_ERROR_NO_INTERFACE; return this; } The next requirement is to create a JavaScript object called Module. This module implements the methods needed for autoregistration and component return type objects. var Module = { firstTime : true, The Boolean firstTime is a flag used only when the component is initially registered: registerSelf: function (compMgr, fileSpec, location, type) { if (this.firstTime) { dump("*** first time registration of Simple JS component\n"); this.firstTime = false; throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; } The Component Manager can do a lot in the registration process, but you have to add some logic for first time registration so the Component Manager has the information it needs. RegisterSelf is called at registration time (component installation) and is responsible for notifying the component
  3. manager of all components implemented in this module. The fileSpec, location, and type parameters can be passed on to the registerComponent method unmolested. Next, register the component with the Component Manager using code like the following example. The parameters include the CID, a description, a progID, and the other parameters you can pass without changing: dump(" ***** Registering: Simple JS component! ****\n"); compMgr.registerComponentWithType(this.myCID, "My JS Component", this.myProgID, fileSpec, location, true, true, type); }, The GetClassObject method produces Factory and SingletonFactory objects. Singleton objects are specialized for services that allow only one instance of the object. Upon success, the method returns an instance of the components factory, which is the implementation class less its interface: getClassObject : function (compMgr, cid, iid) { if (!cid.equals(this.myCID)) throw Components.results.NS_ERROR_NO_INTERFACE;
  4. if (!iid.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; return this.myFactory; }, In the previous list, the member variables myCID and myProgID are the class ID and the human-readable canonical program ID, respectively: myCID: Components.ID("{98aa9afd-8b08-415b-91ed- 01916a130d16}"), myProgID: "@mozilla.org/js_simple_component;1", The member object myFactory is the components factory, which through its own member function, createInstance( ), constructs and returns an instance of the complete component (if the iid parameter is specified and is the correct interface). Otherwise, if no iid parameter is used, the iid of nsISupports is used and an instance of the module is created that will then need a subsequent call to QueryInterface to instantiate the object as a component. myFactory: { createInstance: function (outer, iid) { dump("CI: " + iid + "\n"); if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION;
  5. return (new SimpleComponent( )).QueryInterface(iid); } }, The method canUnload unloads the module when shutdown occurs and is the last function in the module. The componentManager calls the method NSGetModule to initialize these required XPCOM methods and objects: canUnload: function(compMgr) { dump("****** Unloading: Simple JS component! ****** \n"); return true; } function NSGetModule(compMgr, fileSpec) { return Module; } The code in Example 8-4 shows the implementation for the nsISimple interface in its entirety. Example 8-4. JavaScript implementation of nsISimple function SimpleComponent(){} SimpleComponent.prototype = {
  6. get yourName() { return this.mName; }, set yourName(aName) { return this.mName = aName; }, write: function () { dump("Hello " + this.mName + "\n"); }, change: function (aValue) { this.mName = aValue; }, mName: "a default value", QueryInterface: function (iid) { if (!iid.equals(Components.interfaces.nsISimple) && !iid.equals(Components.interfaces.nsISupports)) { throw Components.results.NS_ERROR_NO_INTERFACE; } return this; } }
  7. var Module = { firstTime: true, registerSelf: function (compMgr, fileSpec, location, type) { if (this.firstTime) { dump("*** Deferring registration of simple JS components\n"); this.firstTime = false; throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; } debug("*** Registering sample JS components\n"); compMgr = compMgr.QueryInterface(Components.interfaces.nsICom ponentRegistrar); compMgr.registerFactoryLocation(this.myCID, "Simple JS Component", this.myProgID,
  8. fileSpec, location, type); }, getClassObject : function (compMgr, cid, iid) { if (!cid.equals(this.myCID)) throw Components.results.NS_ERROR_NO_INTERFACE if (!iid.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; return this.myFactory; }, myCID: Components.ID("{98aa9afd-8b08-415b-91ed- 01916a130d16}"), myProgID: "@mozilla.org/js_simple_component;1", myFactory: { createInstance: function (outer, iid) { dump("CI: " + iid + "\n");
  9. if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION; return (new SimpleComponent()).QueryInterface(iid); } }, canUnload: function(compMgr) { dump("****** Unloading: Simple JS component! ****** \n"); return true; } }; // END Module function NSGetModule(compMgr, fileSpec) { return Module; } 8.2.2. Compiling the Component Once you create an IDL source file and a JavaScript implementation file, you need to compile nsISimple.idl into a .xpt type library. 8.2.2.1. Compiling the type library To compile the XPIDL interface file nsISimple.idl, you need to add the path of the XPIDL compiler to your environment. As mentioned earlier, the
  10. XPIDL compiler is located at mozilla/xpcom/typelib/xpidl. Here is the output of a Unix/cygwin/OSX session showing the compilation starting with the source file (nsISimple.idl) created earlier in the chapter. Afterwards, nsISimple.xpt and nsSimple.js are copied to the components directory: $ ls nsISimple.idl nsSimple.js $ PATH=$PATH:/usr/src/mozilla/xpcom/typelib/xpidl $ echo $PATH /sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local /bin:/usr/X11R6/bin:/root/bin:/usr/src/mozilla/xpco m/typelib/xpidl $ export XPIDL_INC=/usr/src/mozilla/xpcom/base $ echo $XPIDL_INC /usr/src/mozilla/xpcom/base $ xpidl -m typelib -w -v -I $XPIDL_INC \ > -o nsISimple nsISimple.idl $ ls nsISimple.idl nsISimple.xpt nsSimple.js $ cp nsISimple.xpt nsSimple.js \ > /usr/src/mozilla/dist/bin/components/ This output illustrates the compilation of the nsISimple.idl source file into the nsISimple.xpt typelib file. The newly compiled typelib file
  11. and the JavaScript implementation file are then copied to the Mozilla distribution components directory where component registration will occur automatically when Mozilla is launched. 8.2.2.2. Creating a Makefile for your component project All previous steps were done manually. You can also create a Makefile to automate this process by using GNU make, in which case you would create a Makefile with the following variables and targets defined: TOP_SRC=/usr/src/mozilla INST_DIR=$(TOP_SRC)/dist/bin/components XPIDL=$(TOP_SRC)/xpcom/typelib/xpidl XPIDL_INC=$(TOP_SRC)/xpcom/base FLAGS=-m typelib -w -v -I $(XPIDL_INC) -o all: $(XPIDL)/xpidl $(FLAGS) \ nsISimple nsISimple.idl install: cp nsISimple.xpt nsSimple.js $(INST_DIR) clean: rm -rf *.xpt uninstall: rm -f $(INST_DIR)/nsISimple.xpt rm -f $(INST_DIR)/nsSimple.js
  12. Remember that you must indent after your targets with a . In this file, which can be used on Unix, Windows using cygwin, or Mac OS X, the TOP_SRC environment variable points to the Mozilla source tree's top-level directory, the INST_DIR points to the directory where the component should be installed, and the XPIDL variables drive the XPIDL executable and its environment and compiler flags. The "all" Makefile target compiles and creates the type library nsISimple.xpt. Note that in addition to the type libraries, the XPIDL compiler compiles header files, Java class files, and special HTML documentation, if necessary. 8.2.3. Testing the Component When you start up xpcshell, the Component Manager finds the new nsISimple component and registers it. The result of your test should look similar to Example 8-5. Example 8-5. Scripting the "simple" component in xpcshell $ cd /usr/src/mozilla/dist/bin/ $ ./run-mozilla.sh ./xpcshell Type Manifest File: /home/petejc/MOZILLA/mozilla/dist/bin/components/xp ti.dat nsNativeComponentLoader: autoregistering begins. nsNativeComponentLoader: autoregistering succeeded *** first time registration of Simple JS component nNCL: registering deferred (0)
  13. ***** Registering: Simple JS component! **** nNCL: registering deferred (0) js>const Simple=new Components.Constructor("@mozilla.org/js_simple_comp onent;1", "nsISimple"); js> var simple=new Simple( ); CI: {ce32e3ff-36f8-425f-94be-d85b26e634ee} js> for(var list in simple) print(list); QueryInterface yourName write change js> simple.yourName; a default value js> simple.yourName="Pete"; Pete js> simple.write( ); Hello Pete null js> simple.change("Brian"); null
  14. js> simple.write( ); Hello Brian null js> simple.yourName; Brian js> quit( ); CanUnload_enumerate: skipping native ****** Unloading: Simple JS component! ****** Once the component is tested and registered as an XPCOM object, you can use JavaScript from a local web page or from the chrome to create an nsISimple object and use it as you would any ordinary JavaScript object: netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect"); var Simple=new Components.Constructor("@mozilla.org/js_simple_comp onent;1", "nsISimple"); var s = new Simple( ); for(var list in s) document.write(list+"\n");
  15. In addition to creating a component in JavaScript, you can implement XPCOM components in C++ and Python. The next sections cover the C++ implementation of the nsISimple interface. 8.2.4. Useful C++ Macros and Types Before you begin working on an actual implementation of a C++ component, familiarize yourself with some of the tools that make C++ programming for XPCOM a little easier. Templates, special types, and macros can ease some of the extra housekeeping that programming XPCOM requires. More tools than we can cover in this introduction are available, but this section reviews some of the most common, including a macro that implements the nsISupports methods QueryInterface, AddRef, and Release, macros for testing nsresults, smart pointers, and special types. 8.2.4.1. The NS_IMPL_ISUPPORTS1_CI macro Rather than having to implement QueryInterface, AddRef, and the Release methods like we did in our JavaScript component, the NS_IMPL_ISUPPORTS macro inserts the implementation code for you. To use this macro for the nsISimple interface, type: NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple) The following lines define this macro: #define NS_IMPL_ISUPPORTS1(_class, _interface) \ NS_IMPL_ADDREF(_class) \ NS_IMPL_RELEASE(_class) \
  16. NS_IMPL_QUERY_INTERFACE1(_class, _interface)
Đồng bộ tài khoản