Creating Applications with Mozilla-Chapter 8. XPCOM- P5

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

lượt xem

Creating Applications with Mozilla-Chapter 8. XPCOM- P5

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- p5', 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ủ đề:

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

  1. Chapter 8. XPCOM- P5 As you can see, the xpidl compiler can do a lot of work for you. The code generated in Example 8-11 is a C++ header file that declares the methods of nsISimple. It provides the class definition, macros for using the interface, and a template for the class implementation, which contains stubbed-out declaratory code that you can paste into your implementation file to quickly get started. Creating the implementation file The implementation file actually contains the C++ code that implements the member functions and properties declared in your interface. For nsISimple, these members are the yourName attribute and the write( ) and change( ) methods. First you need to generate a new UUID for the new implementation class you'll write. Every XPCOM implementation class must have its own UUID: $ uuidgen 79e9424f-2c4d-4cae-a762-31b334079252 As part of the generated file nsISimple.h, all the code stubs you need to get started are ready to be copied and pasted into the C++ source files. You can use those stubs as a guide to implement the component. In a text editor, create a new file called nsSimple.h and enter the code shown in Example 8-12.
  2. To maintain clarity, the C++ implementation class is named nsSimpleImpl, where the default class name generated by the xpidl compiler is nsSimple and the header file, nsSimple.h, is shown in Example 8-12. Example 8-12. The component header file nsSimple.h #include "nsISimple.h" // 79e9424f-2c4d-4cae-a762-31b334079252 #define NS_SIMPLE_CID \ { 0x79e9424f, 0x2c4d, 0x4cae, { 0xa7, 0x62, 0x31, 0xb3, 0x34, 0x07, 0x92, 0x52 } } #define NS_SIMPLE_CONTRACTID ";1" class nsSimpleImpl : public nsISimple { public: nsSimpleImpl( ); virtual ~nsSimpleImpl( ); // nsISupports interface NS_DECL_ISUPPORTS NS_DECL_NSISIMPLE private: char* mName; };
  3. Example 8-12 includes the ID-generated header file nsISimple.h, which holds the C++ declarations for the interface class nsISimple. It then takes the new UUID and breaks it into a class ID struct defined as NS_SIMPLE_CID. Next, it defines the contract ID for this implementation class. The example uses a completely different class ID and contract ID than the one used for the JavaScript component because it's a different implementation class and needs to have it's own unique identification (even though it implements the same interface). Now the example makes the class declaration of the implementation, called nsSimpleImpl, which inherits from nsISimple, defining the class constructor and virtual destructor. NS_DECL_ISUPPORTS is a macro that holds the declaration of our required QueryInterface, AddRef, and Release methods. NS_DECL_NSISIMPLE is created in the generated header file nsISimple.h. It expands to the used interface method declarations. Finally Example 8-12 shows the addition of the char* member variable identified as mName. This variable is used to hold the value of the interface attribute yourName, just as it did earlier in the JavaScript class implementation. Once you have the header file, you are ready to start the implementation source file. With a text editor, create a new file called nsSimple.cpp. As in any C++ source file, you should add the header files required by the implementation: #include "plstr.h" #include "stdio.h"
  4. #include "nsCOMPtr.h" #include "nsMemory.h" #include "nsSimple.h" Start by adding the implementation of our class constructor and destructor: // c++ constructor nsSimpleImpl::nsSimpleImpl( ) : mName(nsnull) { NS_INIT_REFCNT( ); mName = PL_strdup("default value"); } // c++ destructor nsSimpleImpl::~nsSimpleImpl( ) { if (mName) PL_strfree(mName); } Then add the macro NS_IMPL_ISUPPORTS1_CI. As discussed earlier, this macro conveniently implements QueryInterface, AddRef, and Release: NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple); Next you are ready to implement the actual nsISimple interface methods: NS_IMETHODIMP
  5. nsSimpleImpl::GetYourName(char** aName) { NS_PRECONDITION(aName != nsnull, "null ptr"); if (!aName) return NS_ERROR_NULL_POINTER; if (mName) { *aName = (char*) nsMemory::Alloc(PL_strlen(mName) + 1); if (! *aName) return NS_ERROR_NULL_POINTER; PL_strcpy(*aName, mName); } else { *aName = nsnull; } return NS_OK; } A C++ implementation of an IDL method is declared as the type NS_IMETHODIMP. The implementation starts with the getter method GetYourName, which takes a char** parameter for the method's return value. Return values in C++ XPCOM components are marshaled via method arguments because interface implementations must always return a numerical nsresult, as described earlier. To ensure that the aName
  6. parameter is a pointer, use the macro NS_PRECONDITION to warn if null, follow with a null test in the line below, and return the error result code NS_ERROR_NULL_POINTER. Then test whether the member variable mName holds a value. If it does, allocate the necessary memory to accommodate the size of the copy. Then by using PL_strcpy, you can assign the value to the parameter aName. Otherwise, mName is null and you can assign null into aName and return: NS_IMETHODIMP nsSimpleImpl::SetYourName(const char* aName) { NS_PRECONDITION(aName != nsnull, "null ptr"); if (!aName) return NS_ERROR_NULL_POINTER; if (mName) { PL_strfree(mName); } mName = PL_strdup(aName); return NS_OK; } After implementing the getter, implement the setter. Again, use NS_PRECONDITION and then a null test on the aName. If that parameter holds data, you can free it by using PL_strfree and calling PL_strdup. Then assign the new value to class member mName:
  7. NS_IMETHODIMP nsSimpleImpl::Write( ) { printf("%s\n", mName); return NS_OK; } NS_IMETHODIMP nsSimpleImpl::Change(const char* aName) { return SetYourName(aName); } Finally, implement the Write and Change methods by using printf to write the value of mName to stdout and set a new value to mName. Example 8-13 shows the C++ source code in its entirety. Example 8-13. nsSimple.cpp #include "plstr.h" #include "stdio.h" #include "nsSimple.h" #include "nsCOMPtr.h" #include "nsMemory.h" // c++ constructor nsSimpleImpl::nsSimpleImpl( ) : mName(nsnull)
  8. { // NS_INIT_REFCNT( ); // has been depricated use NS_INIT_ISUPPORTS() NS_INIT_ISUPPORTS(); mValue = PL_strdup("default value"); } // c++ destructor nsSimpleImpl::~nsSimpleImpl( ) { if ( ) PL_strfree( ); } // This macro implements the nsISupports interface methods // QueryInterface, AddRef and Release NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple); NS_IMETHODIMP nsSimpleImpl::GetYourName(char** aName) { NS_PRECONDITION(aName != nsnull, "null ptr"); if (!aName) return NS_ERROR_NULL_POINTER;
  9. if ( ) { *aName = (char*) nsMemory::Alloc(PL_strlen( ) + 1); if (! *aName) return NS_ERROR_NULL_POINTER; PL_strcpy(*aName, ); } else { *aName = nsnull; } return NS_OK; } NS_IMETHODIMP nsSimpleImpl::SetYourName(const char* aName) { NS_PRECONDITION(aName != nsnull, "null ptr"); if (!aName) return NS_ERROR_NULL_POINTER; if ( ) { PL_strfree( ); } = PL_strdup(aName);
  10. return NS_OK; } NS_IMETHODIMP nsSimpleImpl::Write( ) { printf("%s\n", ); return NS_OK; } NS_IMETHODIMP nsSimpleImpl::Change(const char* aName) { return SetYourName(aName); } 8.2.6. The nsSimple module code As you needed to do with the JavaScript implementation, you must create the code for the module. The module code abstracts the implementation class and makes the implementation a component library. In your text editor, create a file called nsSimpleModule.cpp and enter the code shown in Example 8-14. Example 8-14. nsSimpleModule.cpp #include "nsIGenericFactory.h" #include "nsSimple.h"
  11. NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleImpl) static NS_METHOD nsSimpleRegistrationProc(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *registryLocation, const char *componentType, const nsModuleComponentInfo *info) { return NS_OK; } static NS_METHOD nsSimpleUnregistrationProc(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *registryLocation, const nsModuleComponentInfo *info)
  12. { return NS_OK; } // For each class that wishes to support nsIClassInfo, add a line like this NS_DECL_CLASSINFO(nsSimpleImpl) static nsModuleComponentInfo components[ ] = { { "A Simple Component", // a message to display when component is loaded NS_SIMPLE_CID, // our UUID NS_SIMPLE_CONTRACTID, // our human readable PROGID or CLSID nsSimpleImplConstructor, nsSimpleRegistrationProc /* NULL if you dont need one */, nsSimpleUnregistrationProc /* NULL if you dont need one */, NULL /* no factory destructor */, NS_CI_INTERFACE_GETTER_NAME(nsSimpleImpl), NULL /* no language helper */, &NS_CLASSINFO_NAME(nsSimpleImpl) }
  13. }; NS_IMPL_NSGETMODULE(nsSimpleModule, components) The final steps for a C++ component Once you have an interface file nsISimple.idl, a C++ source file nsSimple.cpp with its header file nsSimple.h, and a module file nsSimpleModule.cpp, you can create a Makefile like the one shown in Example 8-15. This Makefile can compile the sources into an XPCOM component. A Makefile directs the Mozilla build system to build the sources and install them into the Mozilla dist/bin/components directory. To use the Makefile, run gmake to compile and install the component library file. Example 8-15. Sample Makefile DEPTH = ../../.. topsrcdir = ../../.. srcdir = . VPATH = . include $(DEPTH)/config/ MODULE = xpcom XPIDL_MODULE = simple LIBRARY_NAME = simple IS_COMPONENT = 1
  14. MODULE_NAME = nsSimpleModule REQUIRES = string \ xpcom \ $(NULL) CPPSRCS = \ nsSimple.cpp \ nsSimpleModule.cpp \ $(NULL) XPIDLSRCS = nsISimple.idl include $(topsrcdir)/config/ LIBS += \ $(XPCOM_LIBS) \ $(NSPR_LIBS) \ $(NULL) include $(topsrcdir)/config/ EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
  15. install:: $(TARGETS) To test the newly compiled component, you can use xpcshell like you did for the JavaScript component. Example 8-16 shows a session with xpcshell that tests the new component. Example 8-16. Sample use of component in xpcshell $ ./ ./xpcshell Type Manifest File: /usr/src/commit_mozilla/mozilla/dist/bin/components /xpti.dat nsNativeComponentLoader: autoregistering begins. *** Registering nsSimpleModule components (all right -- a generic module!) nsNativeComponentLoader: autoregistering succeeded nNCL: registering deferred (0) js> var Simple = new Components.Constructor(";1", "nsISimple"); js> var s = new Simple( ); js> s.yourName; default value js> s.write( ); default value
  16. js> s.change('pete'); js> s.yourName; pete js> s.yourName = 'brian'; brian js>
Đồng bộ tài khoản