Please note, this is a STATIC archive of website developer.mozilla.org from November 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Creating the Component Code

 

这一章叙述处理你的组件和XPCOM之间关联的基本代码。让组件被找到和注册是这个章节的目的。在后续章节中,我们开始建立WebLock组件本身的功能。

注:有些部分采用英汉对照的方式。避免翻译的不准确!

Use the Calculator (After Learning Long Division)

You have to write a fair amount of code to create a component library that gets loaded into XPCOM. 一个XPCOM组件起码要实现三个XPCOM要求的接口, 通常还有其他一些. 这一章包含了可能你不会需要的更多代码,不过Using XPCOM Utilities to Make Things Easier会教你一些更简单和优雅的使用通用宏建立XPCOM组件的方式, 本章主要讲述基本的内容。 As in grade school when you learned long division, better tools like calculators come after you figure out what's actually happening. In this case, the long-hand implementation gives us an opportunity to talk about various features of XPCOM.

What We'll Be Working On

The component we'll be working on in this book controls a special mode in your browser that prevents users from leaving the current domain or a set of safe domains. Once enabled, this weblock mode is password protected and persists until it is turned off by the password holder. It can be used to make the browser into a safe viewer for children, or for targeted "kiosk browsing," where the content is restricted to a particular server. Web Lock User Interface shows the icon that is used to activate the web lock mode (leftmost in the status bar) once you have installed the WebLock component and the extra user interface.

 接下来的内容

文章后续的内容,将向读者描述一个使浏览器处在受控模式(web lock mode)的组件,该组件采用密码保护的方式防止用户从当前域或者一组安全的域中离开。这个组件可以使用在为未成年人提供受限内容或者是在一些小型电子浏览器中防止页面跳出特定服务内容。在用户安装了WebLock组件和额外的用户接口后,在状态栏的最左边,如图Web Lock User Interface,可以用图标来激活受控模式(web lock mode)

Web Lock User Interface

Image:web-lock-ui.png

实际上组件WebLock做的大多数事情是准备组件本身,找到需要的XPCOM接口, 并且挂接到现有的Gecko Browser功能.

Component Registration 组件注册

All XPCOM components - whether they're stored in shared libraries (DLLs, DSOs or dylibs), JavaScript files, or some other file - need to be registered before they can be used. Registration is a process that happens in all XPCOM applications, whether they're embedded Gecko clients, Mozilla, Netscape 7, Compuserve, or any other software that uses XPCOM. Registration provides the information that applications need in order to use components properly.

所有的XPCOM 组件- 无论是存储在shared libraries (DLLs, DSOs 还是 dylibs), JavaScript文件,或者其他文件 - 使用前需要被注册. 使用XPCOM的Gecko clients, Mozilla, Netscape 7, Compuserve, 或者其他程序,都需要注册,才能获得合适的组件信息。

The WebLock component must do a number of things to register itself. Specifically, the component library has to contain implementations for the component-related interfaces described in this chapter: nsIModule and nsIFactory, which are entry points for your implementation code.

想要注册 WebLock 组件必须做许多事情. 特别是, 组件库需要包含本章介绍的组件定义的接口: nsIModule and nsIFactory, 这是你的代码入口.

Once your component implements these interfaces, the rest of the registration process itself is simple. Applications typically use regxpcom, described in the next section.

如果你的组件实现了这些接口,注册将变的很容易. 应用中通常使用regxpcom注册, 在下一节描述.

regxpcom 程序

一个明确的注册组件方法是运行regxpcom. 不带任何参数启动regxpcom时, 程序把组件注册在缺省的组件注册表. 我们建议你如果是运行应用, 你可以拷贝你的组件到对应程序安装目录下的components目录. 拷贝好以后,运行regxpcom将注册包含你的组件在内的所有那个目录中的组件.

regxpcom在1.4 或更高版本有一些新的参数. 参看 regxpcom 加<code>-h 选项。

另外的注册方法

Gecko embedding 应用可能提供其他注册组件的方法. XPInstall, 是一个跨平台的安装技术,Mozilla用来安装浏览器和其他组件,这是一个选择。参看Packaging WebLock. 你可以询问你想要扩展的应用的作者看是否有其他扩展方法.

WebLock Module 源代码概览

As we mentioned in the previous section, components have layers. There are three main parts to every XPCOM component. From the innermost and moving outward, the first object is the XPCOM object. This is the object that contains the business logic, that implements functionality such as starting a network download, implementing interfaces that listen to the download progress, or providing a new content type handler. In Weblock, this is the part that brings together various Gecko services and prevents users from leaving the list of acceptable domains. In a way, the factory and module layers are glue to plug the XPCOM object into the larger XPCOM system.

在前面的章节我们提到,组件是分层的.每一个XPCOM组件都有三部分.从内到外, 第一个对象是XPCOM对象. 这个对象包含了交互逻辑, 负责载入network, 执行一个监听载入过程或新content type的接口。. 在Weblock中, 这部分综合了各种Gecko服务并且防止用户离开允许的一些domain. In a way, the factory and module layers are glue to plug the XPCOM object into the larger XPCOM system.

One layer above the object itself is the nsIFactory object. This object provides basic abstraction of the XPCOM object itself. As you can see in Onion Peel View of XPCOM Component Creation , the main accessor for the XPCOM object is CreateInstance, which is expected to return the object that matches a given CID and IID pair.

XPCOM的上层是 nsIFactory 对象. nsIFactory是对XPCOM的基本抽象. 如同你在 Onion Peel View of XPCOM Component Creation中看到的, 通过CreateInstance与XPCOM对象进行交互, 返回一个匹配给定的CID 和IID 的两个对象.

Moving another layer outward is the nsIModule. This interface provides yet another abstraction of the nsIFactory object, and may allow for multiple nsIFactory objects. The key to this interface is that the return type of getClassObject does not have to be an nsIFactory. Instead, the nsIModule can ask for implementation details about the XPCOM object. This is very useful if the caller is required to know information about the component like its threading module, whether or not it's a singleton, its implementation language, and so forth. The interface used in this case is nsIClassInfo. Starting from the outside in, Onion Peel View of XPCOM Component Creation represents the sequence for constructing an XPCOM object.

最外层是nsIModule对象. 他提供了对nsIFactory 的进一步抽象, 而且可能允许多个nsIFactory对象. 关键点是这个接口的方法getClassObject返回的不一定非要是nsIFactory. nsIModule 也可以用来询问 XPCOM 对象的细节. This is very useful if the caller is required to know information about the component like its threading module, whether or not it's a singleton, its implementation language, and so forth. 这是可以使用接口nsIClassInfo. 从外到内, Onion Peel View of XPCOM Component Creation 表示了建立XPCOM对象的顺序.

Onion Peel View of XPCOM Component Creation

Image:xpcom-is-an-onion.png

Before we begin looking at the various parts of the component and how they'll be implemented in the source, let's look at the module in weblock.cpp as a whole to see where we're going. The source we're referring to is listed in its entirety at the end of this chapter (see webLock1.cpp).

WebLock 组件的源代码包含三个类. 为了让WebLock组件工作在 Mozilla中, 你要为WebLock组件建立一个接口, iWebLock, where the actual work specific to the the web locking features happens. 建立 WebLockModule 实现nsIModule接口, 你也要建立 WebLockFactory实现 nsIFactory来建立一个为你的客户处理组件实例的工厂. These three interface implementations - of the component functionality, of the nsIModule interface, and of the nsIFactory interface that creates and manages instances for clients - are the basic sets of code you need to write to create an XPCOM component.

Basic Structure of the WebLock Component Source

The weblock1.cpp source file that defines these classes and the code you need to create a basic component has the following structure:

   * required includes and constants
   * WebLock: public iWebLock
   * WebLockFactory: public nsIFactory
   * WebLockModule: public nsIModule

在XPCOM中, 所有这些类要实现 nsISupports.

更进一步: 需要的 Includes and Constants

Let's take a look at the first several lines of code in the component and discuss what they mean in XPCOM. The includes and definitions at the top of an XPCOM source file can give you an idea about some of the data types and techniques we'll be discussing more in the upcoming chapters.

介绍一下XPCOM的component代码里面前几行的意思。

例如,MOZILLA_STRICT_API是一个变量,它用来遮蔽某些私有的、非XPCOM的头文件。 For example, MOZILLA_STRICT_API is a variable that shields you from certain private, non-XPCOM headers. For example, including nsIComponentManager.idl without MOZILLA_STRICT_API defined will include the following headers, which are not supported across versions (unfrozen):

These variables are picked up by files that do not specify themselves as MOZILLA_STRICT_API.

Includes and Constants in weblock1.cpp

#include <stdio.h>

// may be defined at the project level
// in the makefile
#define MOZILLA_STRICT_API

#include "nsIModule.h"
#include "nsIFactory.h"
 
#include "nsIComponentManager.h"
#include "nsIComponentRegistrar.h"

// use classes to handle IIDs
// classes provide methods for comparison: Equals, etc.
static const nsIID kIModuleIID   = NS_IMODULE_IID;
static const nsIID kIFactoryIID   = NS_IFACTORY_IID;
static const nsIID kISupportsIID = NS_ISUPPORTS_IID;
static const nsIID kIComponentRegistrarIID = NS_ICOMPONENTREGISTRAR_IID;


// generate unique ID here with uuidgen
#define SAMPLE_CID \
{ 0x777f7150, 0x4a2b, 0x4301, \
{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}}

static const nsCID kSampleCID = SAMPLE_CID;

nsIModule.h and nsIFactory.h are required to build your module successfully. They define the module and factory interfaces, and they contain a couple of important macros as well (see the following chapter for information about using these macros). The two other includes, nsIComponentManager.h and nsIComponentRegistrar.h, provide functions such as RegisterFactoryLocation that are required to implement the module and factory classes in your code.

标识符 in XPCOM

一组 nsIID 变量实际上是一些处理XPCOM用来支持客户和组件之间关系的128-bit标识符. The variable kIFactoryIID, for example, provides methods like Equals() that can be used to facilitate comparisons in the code, as in the following example from the Mozilla source:

Using Class Methods to Handle Identifiers

if (aIID.Equals(NS_GET_IID(nsISupports)))
{
  *aInstancePtr = (void*)(nsISupports*)this;
  NS_ADDREF_THIS();
  return NS_OK;
}

最后, SAMPLE_CID 是一个唯一标示组件的 CID . 所有的XPCOM中使用的128-bit数字 - 类和接口 IDs - 都是 UUIDs的例子, or universal unique identifiers, which were discussed in Object Interface Discovery.

Generating CIDs

为组件建立一个CID,你可以使用大多数Unix版本以及Miscrosoft Visual C++都包含的uuidgen 工具. uuidgen is a command-line tool that returns a unique 128-bit number when you call it with no arguments:

$ uuidgen
ce32e3ff-36f8-425f-94be-d85b26e634ee

On Windows, a program called guidgen.exe does the same thing and also provides a graphical user interface if you'd rather point and click. Or you can use one of the special "bots" on IRC in #developers, where you can also get help from human beings.

irc irc.mozilla.org
/join #developers
/msg mozbot uuid

This command makes the bot generate and return a UUID, which you can then copy into your component source code.

Now that we've looked at the preliminaries, it's time to discuss the classes that this module provides and the way that they define the relationships of the component in XPCOM.

Coding for the Registration Process

当 XPCOM 第一次发现你的组件(via XPInstall or regxpcom, both of which are discussed in Component Installation Overview), 第一件事是装载你的库并找到符号NSGetModule. 当这个专用的入口被调用, 它被传送XPCOM's Component Manager和组件存在的共享库位置.

Component Manager是一个是XPCOM实现的用来包含建立对象和提供一些所有组件的综合信息的接口。磁盘的位置是通过另外一个接口 nsIFile传送的. This interface is XPCOM's abstraction of files and directories. An nsIFile object is usually a file or directory on a local volume, but it may represent something on a network volume as well.

nsresult NSGetModule(nsIComponentManager *servMgr,
                     nsIFile* location,
                     nsIModule** result);

XPCOM 需要成功调用 NSGetModule并返回接口nsIModule. 当你写一个 XPCOM 组件, 你实现了 nsIModule to do all of the necessary registration, unregistration, and object creation. nsIModule 有4个方法必须实现.nsIModule has four methods that must be implemented.

The Registration Methods

Two closely related registration methods are declared below.

NS_IMETHOD RegisterSelf(nsIComponentManager *aCompMgr,
                        nsIFile *aLocation,
                        const char *aLoaderStr,
                        const char *aType) = 0;

NS_IMETHOD UnregisterSelf(nsIComponentManager *aCompMgr,
                          nsIFile *aLocation,
                          const char *aLoaderStr) = 0;

RegisterSelf 在组件第一次被XPCOM注册的时候调用. 他只执行一次, which gives you a chance to add any one time setup functionality. The RegisterSelf 允许你的组件告诉XPCOM 你将支持什么功能. 注意所有你在 RegisterSelf 中做的都应该在 UnregisterSelf中撤销.

首先, NSGetModule入口从你的库中被调用, 返回一个指向nsIModule的实现. 然后XPCOM调用RegisterSelf, passing parameters that we'll examine here.

The RegisterSelf Method

The first parameter is the nsIComponentManager, which provides a kind of entry point into managing the registration process. 你可以调用QueryInterface 来查找访问下面所述的其他组件管理接口.

The Many Faces of the XPCOM Component Manager

三个主要的组件管理接口, nsIComponentManager, nsIServiceManager, and nsIComponentRegistrar, are described below:

  • nsIComponentManager - 建立组件并且返回组件实现细节。
  • nsIServiceManager - 提供访问单根组件并且返回单根状态信息。
  • nsIComponentRegistrar - 注册和注销工厂和组件;处理自动注册和发现已经注册的组件列表。

Your RegisterSelf method may call QueryInterface on the nsIComponentManager interface parameter to obtain the nsIComponentRegistrar or nsIServiceManager. nsIServiceManager can be used to obtain a singleton service, which can be useful if you have to register with a service other than the nsIComponentRegistrar if necessary. For example, you may want to get the service that is responsible for an event you want to be notified about. See Getting Called at Startup for an example of this.

第二个参数RegisterSelf是正在注册组件的位置. This parameter is useful when the component needs to know where it has been installed or registered - as, for example, when other files must be stored or accessed relative to the component. This method is only called once, so you have to persist the location if you are going to use it later.

The next two parameters are usually passed into the nsIComponentRegistrar methods and used by XPCOM to determine how to handle the component's registration. The aLoaderStr parameter, which is opaque and should not be modified, distinguishes components that are loaded from the same location specified by the nsIFile parameter. A single ZIP archive may store several XPCOM components, where every component in the archive has the same nsIFile parameter but the aLoaderStr parameter can be used to refer to the location within the ZIP archive.

The last parameter specifies what kind of loader to use on the component. This is reserved as an optimization, for the most part, but it can be a useful way to extend XPCOM. Since XPCOM already knows internally what kind of file it has just loaded and called RegisterSelf on, passing this value to the registration methods is a shortcut for determining what kind of component is being registered.

nsIComponentRegistrar Methods

为了告诉XPCOM这个组件库实现了什么,调用方法:

NS_IMETHOD RegisterFactoryLocation(const nsCID & aClass,
                                   const char *aClassName,
                                   const char *aContractID,
                                   nsIFile *aFile,
                                   const char *aLoaderStr,
                                   const char *aType) = 0;

The last three parameters are the same as the three passed into the RegisterSelf method of nsIModule objects. All you have to do is forward these parameters from your RegisterSelf call into this method, leaving just the first three parameters.

For any class that implements an XPCOM interface, the implementation must have a class identifier if it is to be shared with other parts of code via XPCOM. This identifier, called a CID, uniquely specifies the implementation. This CID can be created via the tool uuidgen on most operating systems, as in The Many Faces of the XPCOM Component Manager above. Given a CID and an IID, you can refer to any class in XPCOM. Consider the following:

Referencing Objects by ID

Image:referencing-objects-by-id.png

In this case, you have two implementations of the nsISupports interface. Each implementation has a separate CID. The interface also as an IID which is the same for both implementations. When specifying implementation A, the two required pieces of information are the CID of A and the IID of the interface that A supports. The code to register such an object is simple:

NS_IMETHODIMP
SampleModule::RegisterSelf(nsIComponentManager *aCompMgr,
                           nsIFile* aPath,
                           const char* registryLocation,
                           const char* componentType)
{
    printf("Hello Mozilla Registration!\n\n");
    nsIComponentRegistrar* compReg = nsnull;
    nsresult rv =
      aCompMgr->QueryInterface(kIComponentRegistrarIID,(void**)& compReg);
    if (NS_FAILED(rv))
        return rv;
    rv = compReg->RegisterFactoryLocation(kSampleCID,
                                          "Sample Class",
                                          nsnull,
                                          aPath,
                                          registryLocation,
                                          componentType);
    compReg->Release();
    return rv;
}

Unregistration follows the same logic. To unregister, all you have to do is pass the CID and the file which is passed into UnregisterSelf.

建立你的组件的一个实例

上面的例子用了 CID, 一旦注册以后,任何使用 XPCOM 的客户都可以访问你的组件,通过contract ID or CID. (Note that RegisterSelf method above does not register a contract ID - it simply passes null. This prevents clients from ever accessing the component with a contract ID.)

为了让其他人访问, 你要公开组件包括它支持的接口的 CID 和/或者 contract ID. 上面的例子中,某人可能通过下面的方法建立一个 Sample对象 :

nsIComponentManager* compManager;  // assume initialized

nsISupports* sample;
compManager->CreateInstance(kSampleCID,
                            nsnull,
                            kISupportsIID,
                            (void**)&sample);

In the above snippet, we assume that the component manager has been initialized. In many cases this value is passed in or easily accessible. 如果还没有建立组件管理者,你总可以调用NS_GetComponentManager()来建立它. XPCOM API Reference中列出了一些全局的XPCOM方法.

The first parameter of the call to CreateInstance specifies the component the client code is looking for, which is the same value passed to RegisterFactoryLocation. The next parameter is for aggregation, which the WebLock component does not support. The third parameter is the interface used to talk to the component. The last parameter is the out variable which will contain a valid object if and only if the method succeeds[non-null-out]. The implementation of CreateInstance will ensure that the result will support the passed IID, kISupportsIID. The type of the variable sample should match the IID passed in as kISupportsIID.

CreateInstance 被调用, XPCOM 查询所有的注册组件来匹配CID. XPCOM然后会装载对应的匹配 CID的组件,如果他还没有被装载的话. XPCOM 然后调用库的 NSGetModule. 最后它调用模块上的 GetClassObject. 这个方法是你来实现的,返回匹配 CID/IID 对的nsIFactory. To prepare your component code, you need to create a factory object for each object that you have registered with XPCOM.

The main function that must be implemented in the nsIFactory interface is CreateInstance. The implementation follows a simple algorithm:

  1. Create the raw object.
  2. If that fails, return an out of memory error code.
  3. Call QueryInterface on the new object.
  4. If that fails, null the out param and free the new object.
  5. Return the nsresult value from QueryInterface.

Often, you don't have to create the object first because the factory implicitly knows what IIDs are supported. When this is not the case, however, doing it this way further abstracts the factories from their concrete classes. If you have a factory that knows every IID supported by the concrete base class, for example, then when you go to add a new supported interface you add this IID comparison in both the factory and the QueryInterface implementation in the concrete class.

NS_IMETHODIMP
SampleFactory::CreateInstance(nsISupports *aOuter,
                              const nsIID & iid,
                              void * *result)
{
  if (!result)
    return NS_ERROR_INVALID_ARG;

  Sample* sample = new Sample();
  if (!sample)
    return NS_ERROR_OUT_OF_MEMORY;

  nsresult rv = sample->QueryInterface(iid, result);

  if (NS_FAILED(rv)) {
    *result = nsnull;
    delete sample;
  }

  return rv;
}

webLock1.cpp

Before any of the improvements and XPCOM tools we describe in the following chapter are brought in, the source code for the WebLock component that implements all the necessary interfaces looks like this.

#include <stdio.h>

#define MOZILLA_STRICT_API

#include "nsIModule.h"
#include "nsIFactory.h"

#include "nsIComponentManager.h"
#include "nsIComponentRegistrar.h"

static const nsIID kIModuleIID = NS_IMODULE_IID;
static const nsIID kIFactoryIID = NS_IFACTORY_IID;
static const nsIID kISupportsIID = NS_ISUPPORTS_IID;
static const nsIID kIComponentRegistrarIID = NS_ICOMPONENTREGISTRAR_IID;


#define SAMPLE_CID \
{ 0x777f7150, 0x4a2b, 0x4301, \
{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}}

static const nsCID kSampleCID = SAMPLE_CID;

class Sample: public nsISupports {
  private:
    nsrefcnt mRefCnt;
  public:
    Sample();
    virtual ~Sample();

    NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult);
    NS_IMETHOD_(nsrefcnt) AddRef(void);
    NS_IMETHOD_(nsrefcnt) Release(void);

};

Sample::Sample()
{
  mRefCnt = 0;
}

Sample::~Sample()
{
}

NS_IMETHODIMP
Sample::QueryInterface(const nsIID &aIID,
                       void **aResult)
{
  if (aResult == NULL) {
    return NS_ERROR_NULL_POINTER;
  }
  *aResult = NULL;
  if (aIID.Equals(kISupportsIID)) {
    *aResult = (void *) this;
  }
  if (*aResult == NULL) {
    return NS_ERROR_NO_INTERFACE;
  }
  AddRef();
  return NS_OK;
}

NS_IMETHODIMP_(nsrefcnt) Sample::AddRef()
{
  return ++mRefCnt;
}

NS_IMETHODIMP_(nsrefcnt) Sample::Release()
{
  if (--mRefCnt == 0) {
    delete this;
    return 0;
  }
  return mRefCnt;
}



// factory implementation class for component
class SampleFactory: public nsIFactory{
  private:
    nsrefcnt mRefCnt;
  public:
    SampleFactory();
    virtual ~SampleFactory();

    NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult);
    NS_IMETHOD_(nsrefcnt) AddRef(void);
    NS_IMETHOD_(nsrefcnt) Release(void);

    NS_IMETHOD CreateInstance(nsISupports *aOuter, const nsIID & iid, void * *result);
    NS_IMETHOD LockFactory(PRBool lock);

};

SampleFactory::SampleFactory()
{
  mRefCnt = 0;
}
SampleFactory::~SampleFactory()
{
}

NS_IMETHODIMP
SampleFactory::QueryInterface(const nsIID &aIID,
                              void **aResult)
{
  if (aResult == NULL) {
    return NS_ERROR_NULL_POINTER;
  }
  *aResult = NULL;
  if (aIID.Equals(kISupportsIID)) {
    *aResult = (void *) this;
  }
  else if (aIID.Equals(kIFactoryIID)) {
    *aResult = (void *) this;
  }

  if (*aResult == NULL) {
    return NS_ERROR_NO_INTERFACE;
  }
  AddRef();
  return NS_OK;
}

NS_IMETHODIMP_(nsrefcnt) SampleFactory::AddRef()
{
  return ++mRefCnt;
}

NS_IMETHODIMP_(nsrefcnt) SampleFactory::Release()
{
  if (--mRefCnt == 0) {
    delete this;
    return 0;
  }
  return mRefCnt;
}


NS_IMETHODIMP
SampleFactory::CreateInstance(nsISupports *aOuter,
                              const nsIID & iid,
                              void * *result)
{
  if (!result)
    return NS_ERROR_INVALID_ARG;

  Sample* sample = new Sample();
  if (!sample)
    return NS_ERROR_OUT_OF_MEMORY;

  nsresult rv = sample->QueryInterface(iid, result);

  if (NS_FAILED(rv)) {
    *result = nsnull;
    delete sample;
  }

  return rv;
}


NS_IMETHODIMP
SampleFactory::LockFactory(PRBool lock)
{
  return NS_ERROR_NOT_IMPLEMENTED;
}






// Module implementation
class SampleModule : public nsIModule
{
  public:
    SampleModule();
    virtual ~SampleModule();

  // nsISupports methods:
  NS_IMETHOD QueryInterface(const nsIID & uuid, void * *result);
  NS_IMETHOD_(nsrefcnt) AddRef(void);
  NS_IMETHOD_(nsrefcnt) Release(void);

  // nsIModule methods:
  NS_IMETHOD GetClassObject(nsIComponentManager *aCompMgr,
                            const nsCID & aClass,
                            const nsIID & aIID,
                            void * *aResult);
  NS_IMETHOD RegisterSelf(nsIComponentManager *aCompMgr,
                          nsIFile *aLocation,
                          const char *aLoaderStr,
                          const char *aType);
  NS_IMETHOD UnregisterSelf(nsIComponentManager *aCompMgr,
                            nsIFile *aLocation,
                            const char *aLoaderStr);
  NS_IMETHOD CanUnload(nsIComponentManager *aCompMgr,
                       PRBool *_retval);

  private:
    nsrefcnt mRefCnt;
};


//----------------------------------------------------------------------

SampleModule::SampleModule()
{
  mRefCnt = 0;
}

SampleModule::~SampleModule()
{
}


// nsISupports implemention
NS_IMETHODIMP_(nsrefcnt)
SampleModule::AddRef(void)
{
  return ++mRefCnt;
}


NS_IMETHODIMP_(nsrefcnt)
SampleModule::Release(void)
{
  if (--mRefCnt == 0) {
    mRefCnt = 1; /* stabilize */
    delete this;
    return 0;
  }
  return mRefCnt;
}

NS_IMETHODIMP
SampleModule::QueryInterface(REFNSIID aIID,
                             void** aInstancePtr)
{
  if (!aInstancePtr)
    return NS_ERROR_NULL_POINTER;

  nsISupports* foundInterface;

  if (aIID.Equals(kIModuleIID)) {
    foundInterface = (nsIModule*) this;
  }
  else if ( aIID.Equals(kISupportsIID) ) {
    foundInterface = (nsISupports*) this;
  }
  else {
    foundInterface = 0;
  }

  if (foundInterface) {
    foundInterface->AddRef();
    *aInstancePtr = foundInterface;
    return NS_OK;
  }

  *aInstancePtr = foundInterface;
  return NS_NOINTERFACE;
}


// Create a factory object for creating instances of aClass.
NS_IMETHODIMP
SampleModule::GetClassObject(nsIComponentManager *aCompMgr,
                             const nsCID& aClass,
                             const nsIID& aIID,
                             void** result)
{

  if (!kSampleCID.Equals(aClass))
    return NS_ERROR_FACTORY_NOT_REGISTERED;

  if (!result)
    return NS_ERROR_INVALID_ARG;

  SampleFactory* factory = new SampleFactory();
  if (!factory)
    return NS_ERROR_OUT_OF_MEMORY;

  nsresult rv = factory->QueryInterface(aIID, result);

  if (NS_FAILED(rv)) {
    *result = nsnull;
    delete factory;
  }

  return rv;
}


//----------------------------------------


NS_IMETHODIMP
SampleModule::RegisterSelf(nsIComponentManager *aCompMgr,
                           nsIFile* aPath,
                           const char* registryLocation,
                           const char* componentType)
{

  nsIComponentRegistrar* compReg = nsnull;

  nsresult rv =
    aCompMgr->QueryInterface(kIComponentRegistrarIID, (void**)&compReg);
  if (NS_FAILED(rv))
    return rv;

  rv = compReg->RegisterFactoryLocation(kSampleCID,
                                        "Sample Class",
                                        nsnull,
                                        aPath,
                                        registryLocation,
                                        componentType);

  compReg->Release();

  return rv;
}

NS_IMETHODIMP
SampleModule::UnregisterSelf(nsIComponentManager* aCompMgr,
                             nsIFile* aPath,
                             const char* registryLocation)
{

  nsIComponentRegistrar* compReg = nsnull;

  nsresult rv = aCompMgr->QueryInterface(kIComponentRegistrarIID, (void**)&compReg);
  if (NS_FAILED(rv))
    return rv;

  rv = compReg->UnregisterFactoryLocation(kSampleCID, aPath);

  compReg->Release();

  return rv;
}

NS_IMETHODIMP
SampleModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload)
{
  *okToUnload = PR_FALSE; // we do not know how to unload.
  return NS_OK;
}

//----------------------------------------------------------------------

extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
                                          nsIFile* location,
                                          nsIModule** return_cobj)
{
  nsresult rv = NS_OK;

  // Create and initialize the module instance
  SampleModule *m = new SampleModule();
  if (!m) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // Increase refcnt and store away nsIModule interface to m in return_cobj
  rv = m->QueryInterface(kIModuleIID, (void**)return_cobj);
  if (NS_FAILED(rv)) {
    delete m;
  }
  return rv;
}
  1. Note: non-null-out
    The CreateInstance method guarantees that if the out variable is non-null, it is valid.

Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.

文档标签和贡献者

标签: 
 此页面的贡献者: ziyunfei, Aspirefhaha, doubleycn, Chioyang, Eskimo root, Secure alex
 最后编辑者: ziyunfei,