Author: Kipp E.B. Hickman

# Gemini Object Model

The gemini object model is a cross platform component object model modelled after win32's IUnknown and COM. We do not support a C API to gemini at this time.

## nsID

Like OSF's DCE, we use an "interface id" which is a unique identifer which names the interface. The nsID and be used as a key into a cross platform registry service to discover an implementation of an interface. Here is the declaration of nsID:

`struct nsID {`
`PRUint32 m0;`
`PRUint16 m1, m2;`
`PRUint8 m3[8];`

`inline nsbool Equals(const nsID& other) const {`
`return`
`(((PRUint32*) &m0)[0] == ((PRUint32*) &other.m0)[0]) &&`
`(((PRUint32*) &m0)[1] == ((PRUint32*) &other.m0)[1]) &&`
`(((PRUint32*) &m0)[2] == ((PRUint32*) &other.m0)[2]) &&`
`(((PRUint32*) &m0)[3] == ((PRUint32*) &other.m0)[3]);`
`}`
`};`

On windows, the "uuidgen" program (provided with Visual C++) can be used to generate these identifiers.

## nsISupports

This is the base class for all component objects. Not all objects are component objects; these rules apply to objects which expose an interface which is shared across dll/exe boundaries. Here is nsISupports:

`typedef nsID nsIID;`
`class nsISupports {`
`public:`
`virtual nsqresult QueryInterface(const nsIID& aIID,`
`void** aInstancePtr) = 0;`
`virtual nsrefcnt AddRef() = 0;`
`virtual nsrefcnt Release() = 0;`
`};`

The semantics of this interface are identical to win32's "COM" IUnknown interface. In addition, the types are carefully mapped and the names are the same so that if necessary we can "flip a switch" and have the windows version (or any other platform that embraces COM) use the native COM IUnknown without source code modification.

## Factory Procedures

Factory procedures use this design pattern

`nsqresult NS_NewFoo(nsIFoo** aInstancePtr, nsISupports* aOuter, ...);`

The return value is a status value (see nsISupports.h for the legal return values); the first argument is a pointer to a cell which will hold the new instance pointer if the factory procedure succeeds. The second argument is a pointer to a containing component object that wishes to aggregate in the Foo object. This pointer will be null if no aggregation is requested. If the factory procedure cannot support aggregation of the Foo type then it fails and returns an error if aggregation is requested.

The following symbols are defined for standard error return values from `QueryInterface` and from factory procedures:

`#define NS_FAILED(_nsresult) ((_nsresult) < 0)`
`#define NS_SUCCEEDED(_nsresult) ((_nsresult) >= 0)`

`// Standard "it worked" return value`
`#define NS_OK 0`

`// Some standard error codes we use`
`#define NS_ERROR_BASE ((nsresult) 0xC1F30000)`
`#define NS_ERROR_OUT_OF_MEMORY (NS_ERROR_BASE + 0)`
`#define NS_ERROR_NO_AGGREGATION (NS_ERROR_BASE + 1)`
`#define NS_NOINTERFACE ((nqresult) 0x80004002L)`

## nsIFactory

Factory classes should eventually replace factory procedures for major classes. They provide an easy mechanism for placing code in DLLs. The nsIFactory class is as follows:

`class nsIFactory: public nsISupports {`
`public:`

`virtual nsresult CreateInstance(const nsIID &aIID,`
`nsISupports *aOuter,`
`void **aResult) = 0;`
`virtual void LockFactory(PRBool aLock) = 0;`

`};`

This interface is again identical to the COM version. More on registering factories shortly.

## Error Handling

Because no exceptions are returned, error handling is done in the traditional "error status value" method.

## Cross Platform Registry

A cross platform registry was written for the SmartUpdate feature of Communicator. We will investigate it's usefulness for our purposes.

## Library Management

NSPR 2.x provides the cross platform mechanism for loading and unloading libraries, and run time linking.