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.