ActiveX Interface for ObjectStore

Chapter 3

Using OSAX with Microsoft ATL

The Microsoft Active Template Library (ATL) is a set of template-based C++ classes that you can use to create small, fast Component Object Model (COM) objects. OSAX supports ATL as a way to create COM interfaces for persistent objects stored in ObjectStore. The ATL approach is an alternative to the approach described in Chapter 2, Building OSAX Object Servers, which is based on a type description file. Using ATL requires more C++ expertise, but ATL provides more flexibility for customizing COM interfaces.

When using OSAX with the ATL interfaces, you define COM interfaces using normal ATL techniques, classes, and interfaces. You then connect them to ObjectStore objects using template classes provided by the ActiveX interface. The resulting control is linked with the ObjectStore and OSAX run-time libraries.

The following facilities are described in this chapter:

An ATL-defined control that uses ObjectStore must be linked with osax.lib. The type description file and osgentyp are not needed. However, osgentyp produces code that uses the same interfaces as described in this chapter and can be used to generate initial code for an ATL-based project. Type description files and the osgentyp utility are described in Chapter 2, Building OSAX Object Servers.

OSAX and ATL Concepts

The following sections define the terms and concepts used in this chapter.

Terminology

The following terms are used to describe OSAX and ATL:

OSAX Object Servers

A typical OSAX object server consists of a top-level object with methods that are used to access the server's other objects. The top-level object has a COM class. The OSAX client creates the top level object with the class factory for the COM class. The top-level object establishes the context for the other objects, so that all of the client's objects execute in a single context.

An OSAX object server is the same as a standard ATL object server, except that a different module class is used, additional header files are needed, and there is an additional library. An OSAX object server may be a DLL file, an .exe file, or an NT service.

OSAX Classes

OSAX classes use a threading model of Both. They are ATL classes with the additional public base template classes CExceptionTranslator and IOSAXContextInformationImpl. In addition, the interface IOSAXContextInformation must be added to the interfaces listed in the COM_MAP section of the class.

OSAX Methods

OSAX methods are ATL methods with their bodies wrapped by macros that establish exception translation, fault-handling, and context management. The method bodies are preceded by OSAX_BEGIN_METHOD and followed by OSAX_TRANSLATE_EXCEPTIONS and OSAX_END_METHOD. The macro OSAX_END_METHOD includes a return, so no explicit return is used after it. A method looks like this:

    STDMETHODIMP CAuthor::get_Name(IOSAXString * * pVal)
    {
        OSAX_BEGIN_METHOD(IID_IAuthor)

        // method body

        OSAX_TRANSLATE_EXCEPTIONS
        OSAX_END_METHOD
    }

OSAX Instances

OSAX instances and their related classes are the most important OSAX objects. OSAX instances are fixed references to C++ objects that are valid across transactions. OSAX instances are created only by OSAX. When the C++ objects are persistent, OSAX instances hold the transient state associated with the persistent object. For example, an OSAX instance holds the reference count, because the reference count is only used transiently and must be available even when a transaction is not in progress.

For a client, an OSAX instance container is like an OSAX instance, except that the reference to the C++ object can be changed.

OSAX instances and instance containers are both defined by a single OSAX class. If the OSAX class supports a class factory, then the class factory will create instance containers. In addition, the normal ATL methods, such as CreateObject, can be used to allocate instance containers. OSAX methods call the internal SetDataImpl method to change the C++ object being referenced. SetDataImpl will fail if called on an instance instead of an instance container.

The following illustrates OSAX instances:

OSAX Instance Classes

Every OSAX instance must have an associated OSAX instance class. The same OSAX class may be used for both, or one OSAX class may be used for each. The osgentyp utility produces separate OSAX classes for the instance and instance class; see The osgentyp Utility in Chapter 2, Building OSAX Object Servers.

An OSAX instance class is an object that supports constructors and methods applicable to the entire C++ class, rather than to specific objects of the class. The OSAX class for the OSAX instance includes the public template base CInstanceImpl and adds the interface IOSAXInstanceInformation, in addition to the standard additional OSAX base classes and interfaces. Instance implementations access the referenced C++ object through a member called data. data behaves like a pointer to the referenced C++ object. The public nested class CDataPtr implements data. The CDataPtr has a number of useful constructors that let it be used to access the referenced C++ object from the methods of other OSAX objects, and to obtain OSAX instances for C++ pointers.

The OSAX class for the instance class includes the public base template class CInstanceClassImpl and exposes the additional interface IOSAXType. The top-level server object normally includes methods that return an object for each of the instance classes.

Implementing an Object Server with ATL

The following procedure implements an OSAX object server directly in ATL:

  1. Use the ATL COM AppWizard to make a skeleton ATL project.

  2. Make the project-level changes to enable OSAX.

  3. Add ATL classes.

  4. Add base classes, interfaces, etc. to the class definitions to convert them to OSAX classes, OSAX instances, and OSAX instance classes

  5. Add methods using the ATL class wizard.

The following sections explain each step in more detail, using a variation of the Books example; see A Tour of the Books Example in Chapter 1, Overview of the ActiveX Interface for ObjectStore. The project for the Books example (see the Visual C++ project file c:\odi\osax\examples\steps\stepn\books.dsw) shows the result at the completion of each of the following steps. In the pathnames in the following descriptions, replace Books with the name of your server.

Step 1. Use the ATL COM AppWizard.

Use the ATL COM AppWizard to create the skeleton ATL project. In the example for this procedure, the server is implemented as a dynamic link library (DLL).

Step 2. Make project-level changes.

For each configuration you build, make the following changes:

In the Link tab in category General, add ostore.lib to the front (left side) of the Object/library modules.

In the stdafx.h file, make these changes:

In books.cpp, change:

    CComModule _Module;
to:

    OSAX::COSAXModule _Module;
Click on File|Save All to save the changes to your project.

Step 3. Add ATL classes.

You will need a top-level object that clients create to access your server objects and objects that represent your C++ objects. In this procedure, we will parallel the Books example that uses the type description file, except that for each C++ class we will combine the ATL classes for the OSAX instance and the OSAX instance class. We also add one class to simplify the Books collection. Thus, we will have five ATL classes.

For the top-level object, we use the name OSAXBooks and a ProgID of OSAX.ATLBooks. We use slightly different interfaces from those used in the type description version of the Books example. Under attributes, we select a threading model of Both and support ISupportErrorInfo. We won't support aggregation, and the dual interface is optional. We use the same settings for the other objects.

Step 4. Add base classes, etc.

Every OSAX class needs to include the template base classes CExceptionTranslator and IOSAXContextInformationImpl. CExceptionTranslator implements the translation of TIX and C++ exceptions into COM exceptions. Its template argument is the ATL class. IOSAXContextInformationImpl supplies the context information that manages sessions with the storage system. Its template argument is the ATL class. Each of these classes must add:

    COM_INTERFACE_ENTRY(IOSAXContextInformation)
to the COM_MAP section of the class definition.

Every ATL class that implements an OSAX instance class needs to include the template base class CInstanceClassImpl. Since we are using one ATL class to implement each instance and instance class, each of these classes will require CInstanceClassImpl. It takes two template arguments, the ATL class that implements the instance class, and the ATL class that implements the instance. In the Books example, these are the same.

The template base class implements the interface IOSAXType, so you must add:

    COM_INTERFACE_ENTRY(IOSAXType)
to the COM_MAP section of your classes. Also, because IOSAXType is a dispatch interface, you must modify the entry for IDispatch to tell it which IDispatch interface to use for your class, by using:

    COM_INTERFACE_ENTRY2(IDispatch,IMyClass)
where IMyClass is the dispatch interface you want to serve as the default IDispatch interface.

Each instance class should add:

    OSAX_CLASS_INTERFACE(IInstanceClass)
to its class definition. The area above the COM_MAP is a good place to add macros like this. The macro defines an accessor for the instance class.

Add:

    COM_INTERFACE_ENTRY(IOSAXInstanceInformation)
to the COM_MAP section of your class.

Each instance class should also add:

    OSAX_TYPE_NAME("C++ type")
This defines an accessor the name of the type, which can be used to obtain an os_typespec for persistent allocation. Use of OSAX_TYPE_NAME is optional.

Every ATL class that implements an OSAX instance needs to include the template base class CInstanceImpl, which takes three arguments:

In this procedure, the first two arguments are the same. You will also need to include the header files for your C++ classes. In this example, include directives for the header files were inserted in stdafx.h.

Each instance class should add the following to its definition:

    OSAX_INTERFACE_CONVERSION(IInstance)
The part of the class definition near the COM_MAP is a good place for this. OSAX_INTERFACE_CONVERSION defines a conversion from the ATL class to the specified interface. This conversion is used when writing methods.

The ATL class definitions for your instance classes should add:

    DECLARE_GET_CONTROLLING_UNKNOWN()
You can add it just before the COM_MAP section.

Finally, you must include the header files for your C++ classes since the ATL instance classes need to see the types. In this example, the file persistent.h was added to the project.

Add the following line to the .idl file:

    import "osaxint.idl";

Step 5. Add methods.

We can use Class View to add a default property called Name to the IAuthor interface. The IDE will add the method and the class definition to the .idl file, and generate a stub method body. In this example, the property's value will be an IOSAXString*.

The Name method will access the char* value of the data associated with the IAuthor interface pointer. The method's implementation must first access the C++ Author*, then get the char* name, get an IOSAXString* for the char*, and return an appropriate HRESULT. At the same time, any exceptions from ObjectStore must be translated to COM exceptions, and the ObjectStore fault handler must be enabled.

OSAX provides three macros to perform fault-handling and exception translation. At the beginning of your method you use OSAX_BEGIN_METHOD, which needs the interface IID as an argument. Your method body follows, and then you must provide the macros OSAX_TRANSLATE_EXCEPTIONS and OSAX_END_METHOD. OSAX_END_METHOD will return an appropriate HRESULT, so you do not need to do anything special to return a value from the method. The method looks like this:

    STDMETHODIMP CAuthor::get_Name(IOSAXString * * pVal)
    {
        OSAX_BEGIN_METHOD(IID_IAuthor)
        OSAX_TRANSLATE_EXCEPTIONS
        OSAX_END_METHOD
    }
OSAX provides a member variable called data that is a smart pointer that acts like a pointer to the data referenced by the OSAX object. To access the m_strName member of the object, all you need to write is:

    data->m_strName
The OSAX instance class implementation provides useful methods for obtaining OSAX instances for C++ values. The OSAX_INTERFACE_CONVERSION macro defines a conversion function from the ATL class to an interface pointer. C++ constructors and conversion operators permit the conversion function to work directly on the C++ object to be referenced by the OSAX instance. The class OSAX::COSAXString implements IOSAXString, and its GetInterfacePtr member takes a char* and an IOSAXString** as arguments and returns an HRESULT. If it succeeds, the contents of the IOSAXString** argument will be set to the OSAX instance for the char* pointer. The complete get_Name method looks like:

STDMETHODIMP CAuthor::get_Name(IOSAXString * * pVal)
{
    OSAX_BEGIN_METHOD(IID_IAuthor)
        return COSAXString::GetInterfacePtr(data->m_strName, pVal);
    OSAX_TRANSLATE_EXCEPTIONS
    OSAX_END_METHOD
}
The methods for CAuthor, CBook, and CBookElt are all similar.

The OSAX_CLASS_INTERFACE macro defines the accessor GetClassInterfacePtr, so the method just needs to call it (the object server in the Books example exposes only the BookElt instance class):

STDMETHODIMP COSAXBooks::get_BookEltClass(IBookElt * * pVal)
{
    OSAX_BEGIN_METHOD(IID_IOSAXATLBooks)
        return CBookElt::GetClassInterfacePtr(pVal);
    OSAX_TRANSLATE_EXCEPTIONS
    OSAX_END_METHOD
}
The top-level server object needs a method to return an IOSAXObjectStore interface pointer. OSAX provides a function for this, so the method is defined as:

STDMETHODIMP COSAXBooks::get_ObjectStore(IOSAXObjectStore * * pVal)
{
    OSAX_BEGIN_METHOD(IID_IOSAXATLBooks)
        return GetOSAXObjectStore(pVal);
    OSAX_TRANSLATE_EXCEPTIONS
    OSAX_END_METHOD
}
In the file stdafx.h, add:

    #include <ostore/ostore.hh>
just before the include directive for osax.h to enable ObjectStore-specific definitions in osax.h.

In the header file persistent.h, add:

    static os_typespec* get_os_typespec()
to each of the C++ classes.

Finally, add a custom build rule for ossg. To add the custom build rule, add a text file to the project. In this example, the name of the text file is schema.scm. Under Project Settings, set the settings for All Configurations, and select the file schema.scm. Add the following ossg line:

ossg -asdb $(OutDir)\schema.adb -asof $(IntDir)\schema.obj    $(InputDir)\$(InputPath)
           /I $(InputDir) /MD /D_DLL /DWIN32
For the targets, use:

$(IntDir)\schema.obj   $(OutDir)\schema.adb
The schema file lists the C++ types in your database. If you want to allow more than one OSAX object server to be used at a time, mark the schema file as a DLL schema by including

OS_SCHEMA_DLL_ID(id)
where id can be in either of the following:

ObjectStore uses id to load the DLL when an object defined by dllname or componentname is referenced.

The server will have a top-level object method that creates an empty book list, represented by a BookElt that has a NULL Book and a NULL next element in the list.

The CinstanceImpl template base class used for OSAX instances defines a nested base class called CDataPtr. The CDataPtr class is the class of the smart pointer called data. It has constructors that will initialized it from variants, C++ pointers, and interface pointers. In this example, we have an IOSAXDatabase* interface pointer, and need an os_database*. COSDatabase is the class that implements IOSAXDatabase for ObjectStore databases, so we can use the CDataptr to get a smart pointer and the smart pointer can be converted to an os_database*, as follows:

    os_database* pDatabase = COSDatabase::CDataPtr(pDb); 
The complete method is:

STDMETHODIMP COSAXBooks::CreateBookList(IOSAXDatabase * pDb, BSTR bstrName,
                                                                                           IBookElt * * ppBookElt)
{
    USES_CONVERSION;
    OSAX_BEGIN_METHOD(IID_IOSAXATLBooks)
        os_database* pDatabase = COSDatabase::CDataPtr(pDb);
        os_database_root* pRoot = pDatabase->create_root(OLE2A(bstrName));
        BookElt* pBookElt = new(pDatabase,BookElt::get_os_typespec()) BookElt;
        pRoot->set_value(pBookElt,BookElt::get_os_typespec());
        return CBookElt::GetInterfacePtr(pBookElt,ppBookElt);
    OSAX_TRANSLATE_EXCEPTIONS   OSAX_END_METHOD
}
OSAX provides special overloadings of the new operator that can be used with IUnknown and VARIANT placement arguments. The object server in the Books example exposes a method for creating a new Author in a segment or database, passed in an optional VARIANT pointer.

The method definition is:

STDMETHODIMP COSAXBooks::CreateAuthor(BSTR bstrName, VARIANT where,
                                                                                       IAuthor * * ppAuthor)
{
    USES_CONVERSION;
    OSAX_BEGIN_METHOD(IID_IOSAXATLBooks)
        // Copy the ANSI version of the name to its permanent location
        char* strNameIn = OLE2A(bstrName);
        ULONG nLengthName = strlen(strNameIn)+1;
        char* strNameAuthor = new(where, COSAXString::InstanceClass(), nLengthName)
                                                              char[nLengthName];
        strcpy(strNameAuthor,strNameIn);

        // Allocate a new Author
        Author* pAuthor = new(where,CAuthor::InstanceClass()) Author(strNameAuthor);
        return CAuthor::GetInterfacePtr(pAuthor,ppAuthor);
    OSAX_TRANSLATE_EXCEPTIONS
    OSAX_END_METHOD
}

Creating OSAX Instances

Class factories can be used by ActiveX controllers to create OSAX instances. When a class factory creates an OSAX instance, the instance is not initialized. OSAX instance initialization methods can be used to set the instance to a new or existing C++ object.

In the following example, Aut is an uninitialized Author OSAX instance. The Storage property specifies where the persistent state is allocated.

    Dim Aut As New Author
    Set Aut.Storage = MyDatabase
    Aut.Name = "Samuel Clemens"
You can also use other approaches. In the following example, an OSAX instance is initialized to another OSAX instance:

    Dim Aut1 As New Author
    Aut1 = Aut
Notice that it is not

    Set Aut1 = Aut
which would change the value of the variable Aut1. Here, Author has a default value setter that is defined to set the reference.

A constructor style can be used as follows:

    Dim Aut As New Author
    Aut.Create(MyDatabase,"Samuel Clemens"
An alternative approach is to have a separate OSAX class object:

    Dim Aut As Author
    Set Aut = AuthorClass.Create(MyDatabase,"Samuel Clemens")

OSAX Instances for Existing C++ Objects

OSAX methods return OSAX instances that refer to C++ objects. You can set an object variable to the result of the method. If the class supports assignment, you can also set the C++ reference of an existing object to the result:

    Dim Aut As Author
    Dim Aut1 As New Author
    'Set Aut variable to the returned object
    Set Aut = Writers.GetAuthor("Elbert Hubbard")
    'Set C++ reference of Aut1 to the returned object
    Aut1 = Writers.GetAuthor("Nicolas Bourbaki")
Why would you want to use one approach instead of another? If you are using the Microsoft Transaction Server (MTS), your objects may be under its control. You can initialize them by setting their C++ references to another OSAX instance, similar to the way you initialize other objects by loading them from a file.

Object Deletion

A class can support object deletion. When an OSAX instance is marked for deletion, the referenced C++ object is deleted on final release. See DeleteDataOnFinalRelease in Methods of the CInstance::CDataPtr Class.

API Reference

OSAX Methods

The general format of an OSAX method is:

OSAX_BEGIN_METHOD(IID)
     // method body
[optional exception translators]
OSAX_TRANSLATE_EXCEPTIONS
OSAX_END_METHOD
The argument IID should be the IID of the interface implemented by the method. These macros enable the ObjectStore fault handler, perform synchronization, establish appropriate transaction context, and translate C++ and TIX exceptions into ActiveX exceptions.

Exceptions

Exceptions are translated via Translate methods defined by the base class CExceptionTranslator. The Translate method extract appropriate information from the exception and call AtlReportError. You may define your own translate methods in your class if the default behavior is not appropriate.

Optional Exception Translators
The optional exception translators can be used to translate exceptions that are not normally translated by OSAX.

OSAX_HANDLE_EXCEPTION(H)
If a C++ exception derived from the class exception is thrown, an ActiveX exception is formed from the error description and the method returns an HRESULT of H.

OSAX_HANDLE_EXCEPTION(E, e)     exception handling code
If a C++ exception derived from E is thrown, e is bound to a reference to the exception. You can handle the exception in an arbitrary way.

Raising Exceptions
OSAX provides Error methods corresponding to AtlError. These can be called anywhere within the scope of an OSAX method body. They will throw to the OSAX exception handler and then call the corresponding AtlError function. The functions that take an IID or CLSID will use the value for the method if GUID_NULL is used as an argument to Error.

Template Classes

All OSAX classes must use the following as a base class:

template<class T> class IOSAXContextInformationImpl
The argument T should be the ATL class that implements your object. The class is used internally by OSAX to associate OSAX objects with appropriate transactions.

All OSAX instance class classes must use the following class as a base class:

template <class CInstanceClass, class CInstance> class CInstanceClassImpl
The template arguments are the class of the instance class and the class of the instance. The class implements the IOSAXType interface.

template <class CInstanceClass, class CInstance, class C> class CInstanceImpl
All classes that implement OSAX instances must include this base class. It defines the CInstance::CDataPtr class and many methods used internally by OSAX.

OSAX Instance Data Members

Every OSAX instance and instance container has a data member called data, which is implemented by the class CInstance::CDataPtr. data is a reference to the C++ object. In the descriptions that follow, CInstance is the class that implements your instance.

static CInstance::GetInterfacePointer(const CInstance::CDataPtr&,I** ppI)
The GetInterfacePointer methods are used to obtain an interface pointer for an OSAX instance or instance container. They are defined by the OSAX_INTERFACE_CONVERSION macro.

static CInstance::GetClassInterfacePtr(I** ppI)
The GetClassInterfacePtr method is used to obtain an interface pointer for the OSAX instance class associated with CInstance. The method is defined by OSAX_CLASS_INTERFACE.

HRESULT CInstance::SetDataImpl(IUnknown* pUnk)
Use SetDataImpl to change which C++ object is associated with an instance container. The context associated with pUnk will become the context for the instance container. If SetDataImpl is called by an OSAX instance, E_INVALIDARG is returned.

static void CInstance::OnDeleteData(C* pC)
This method is called on FinalRelease when CInstance::DeleteDataOnFinalRelease has been called to mark the object for deletion on FinalRelease. It deletes pC. You may define override this definition in the CInstance class to do something different.

HRESULT CInstance::DeleteDataOnFinalRelease(VARIANT_BOOL bDelete)
Use this method to specify whether or not the C++ data should be deleted upon final release of the OSAX instance.

static CComPtr<IOSAXInstanceClass> CInstance::InstanceClass()
Returns the InstanceClass (an internal OSAX object) for use with the OSAX operator new.

Methods of the CInstance::CDataPtr Class

The CDataPtr class is like a transient reference to the C++ object referenced by an OSAX instance. CDataPtr constructors are used to obtain OSAX instances from C++ pointers, as well as to obtain C++ pointers from OSAX instance interface pointers.

In the descriptions that follow, C is the class of the C++ type associated with CInstance.

CInstance::CDataPtr::CDataPtr()
Creates a reference to a NULL pointer.

CInstance::CDataPtr::CDataPtr(C* pC)
Obtains the OSAX instance for pC and wraps it in CDataPtr.

CInstance::CDataPtr::CDataPtr(IUnknown* pUnk)
If pUnk is an OSAX instance, CDataPtr will refer to its C++ object.

If pUnk supports IATKRefString (an ATK object), then CDataPtr will reference the C++ pointer referenced by the ATK object.

CInstance::CDataPtr::CDataPtr(VARIANT& rvar, const CDataPtr& refDefault)
If rvar is an optional argument to a method, and the argument was supplied by the caller, then it should be an interface pointer, and the CDataPtr(IUnknown* pUnk) procedure will be used.

If rvar was not supplied by the called, then the CDataPtr will be initialized to the C++ pointer referenced by refDefault.

C* CInstance::CDataPtr::operator -> () const
CInstance::CDataPtr::operator C* () const
C* CInstance::CDataPtr::Resolve() const
All these return the referenced C++ pointer. You may need to explicilty use Resolve in some cases where a conversion operator can not be applied.

CDataPtr& CInstance::CDataPtr::operator = (const CDataPtr& rDataPtr)
Changes the referenced C++ pointer to that of rDataPtr. Do not assign to the data member of an OSAX instance. Instead, use the method CInstance::SetDataImpl.

bool CInstance::CDataPtr::operator !() const
Returns true if CDataPtr references a NULL pointer.

Using OSAX Instances to Implement Other Object Servers

You can use an OSAX instance that is implemented in another OSAX object server, as long as the object server is an Inproc server. You do this by using the class CConversionImpl.

template <class CInstance, class C, const GUID* G>
class CConversionImpl
C is the C++ type referenced by the OSAX instance, and G is the CLSID for the instance class. CInstance is the class name you will use as the class name in the server you are using. It does not need be the same as the class name where the server is actually implemented.

You must add OSAX_INTERFACE_CONVERSION and OSAX_CLASS_INTERFACE macros for the relevant interfaces, and a constructor.

Examples can be found in osax.h. For example, IOSAXString is implemented in an OSAX object server and exposed to other object servers in osax.h as:

class COSAXString : public 
CConversionImpl<COSAXString,char,&CLSID_OSAXString>
{
public:
    COSAXString (IUnknown* pUnk) : ConversionImpl(pUnk){}
    OSAX_INTERFACE_CONVERSION(IOSAXString)
    OSAX_CLASS_INTERFACE(IOSAXStringConstructor)
};

Collections

OSAX provides template base classes to expose ObjectStore collections as automation collections that can be used with Visual Basic's For Each...Next statement.

template <class IDispatchImplCollection, class CInstance, class TElement,
                    class IElement>
class IOSAXCollectionImpl
Use this as a base class instead of IDispatchImpl if you want to expose a class derived from os_Collection as a collection.

IDispatchImplCollection is an IDispatchImpl template instantiation for your collection interface. CInstance is your ATL class. TElement is the class that implements the OSAX instances for the elements of the collection. IElement is the interface to use for methods that accept elements as arguments.

template <class IDispatchImplCollection, class CInstance, class TKey, class IKey,
                    class TElement, class IElement>
class IOSAXDictionaryImpl
Use this as a base class instead of IDispatchImpl if you want to expose a class derived from os_dictionary as a collection.

IDispatchImplCollection is an IDispatchImpl template instantiation for your collection interface. CInstance is your ATL class. TKey is the ATL class that implements the keys. IKey is the interface for the keys. TElement is the ATL class that implements the elements. IElement is the interface for the elements.

Macros for Class Definitions of OSAX Instances and Conversions

OSAX_INTERFACE_CONVERSION(I)
Add this macro to the class definition of your instance to define the method:

    CInstance::GetInterfacePointer(const CDataPtr&,I** ppI)
OSAX_CLASS_INTERFACE(I)
Add this macro to the class definition of your instance to define the method:

    CInstance::GetClassInterfacePtr(I** ppI)
OSAX_TYPE_NAME(name)
Add this macro to the class definition of your instance to specify the name of the C++ class. This name can be used to obtain an os_typespec.

OSAX_OBJECTSTORE_TYPESPEC
Add this macro to the class definition of your instance to allow it to get a typespec from the C++ class's get_os_typespec method.

OSAX_NO_OBJECT_TABLE
Add this macro to the class definition of your instance to make it not use an object table. This means that there may be multiple OSAX instances for the same C++ object.

Global Functions

HRESULT OSAX::DeleteDataOnFinalRelease(IUnknown* pUnk, VARIANT_BOOL bFree)
Use this method if you want the C++ object referenced by pUnk to be deleted upon final release of pUnk.

bool OSAX::Equal(IUnknown* pUnk1, IUnknown* pUnk2)
Returns true if pUnk1 and pUnk2 refer to the same C++ object.

HRESULT OSAX::OnEndPage()
Call this in servers used by ASP if you want them to abort the transaction when a page is ended.

HRESULT OSAX::GetOSAXObjectStore(IOSAXObjectStore**)
Call this to obtain an IOSAXObjectStore interface pointer.

Overloadings of Operator new

void* operator new(size_t nSize, IUnknown* pUnkWhere, IOSAXInstanceClass* pInstanceClass)
void* operator new(size_t nSize, IUnknown* pUnkWhere, IOSAXInstanceClass* pInstanceClass,
                                     size_t nElts)
void* operator new(size_t nSize, VARIANT& rvar, IOSAXInstanceClass* pInstanceClass)
void* operator new(size_t nSize, VARIANT& rvar, IOSAXInstanceClass* pInstanceClass,
                                     size_t nElts)
OSAX provides these overloadings of operator new to simplify the allocation of C++ objects. You do not need to these news. The pUnkWhere or rvar arguments specify where allocation should take place. If they are a segment or database, allocation will take place in the segment or database. If they are an OSAX instance, allocation will take place in the same segment as the referenced data. Otherwise, transient allocation is used.

Use the nElts versions for vector allocation. The nElts argument specifies the number of elements.



[previous] [next]

Copyright © 1998 Object Design, Inc. All rights reserved.

Updated: 03/18/98 13:55:43