Page 1 of 1

Microsoft : Working With Component Object Model Objects - Part II The class factory method Rate Topic: -----

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 03 April 2010 - 01:02 PM

Microsoft : Working With Component Object Model Objects - Part II

The Class Factory

In the previous tutorial Microsoft : Working With Component Object Model Objects - Part I, we looked at the IUnknown interface, the creation of an IFoo interface derived from IUnknown, and the implementation of the IUnknown/IFoo interfaces through a foo object.

This tutorial looks at another major player in the set of COM objects known as the IClassFactory interface. This interface also is derived from IUnknown but extends the three pure virtual methods QueryInterface, AddRef and Release by a further two known as CreateInstance and LockServer.

As it's name suggests, the IClassFactory object is where COM objects are created (where else but in a factory!). Now, remember I said in the first tutorial, all COM objects needed a Universal Unique Identifier (UUID). IClassFactory receives a request for an object to be created through the CreateInstance method. It knows what objects it can create, and can therefore produce an object of the type requested by means of the UUID. We shall now see how IClassFactory can create one of two different types of object and return their interface using their UUID. The interfaces that can be requested are IFoo and IFoo2. We shall discuss the code in a little more detail in a moment, but for now here is the code.

#include <windows.h>

interface __declspec(uuid("E2F7AF75-C6CF-4A80-8968-793CB864BCD9")) IFoo : public IUnknown {
    public:
        virtual HRESULT STDMETHODCALLTYPE foobar() = 0;
};

interface __declspec(uuid("34A0E88E-9B96-4777-812C-A62CDAF53996")) IFoo2 : public IFoo {
    public:
        virtual HRESULT STDMETHODCALLTYPE foobar() = 0;
};

interface  __declspec(uuid("8DE60F70-2C77-4C0A-9DF9-6E75D18A92AA")) IFooClassFactory : public IClassFactory { };

// Implementation of the foo object
class foo : public IFoo {
    private:
        DWORD reference_count;
    public:
        foo() : reference_count(0) { }
        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID * object) {
            *object = NULL;
            if ( riid == IID_IUnknown || riid == __uuidof(IFoo) ) {
                *object = this;
                this->AddRef(); 
            }
            if ( *object == NULL ) return E_NOINTERFACE;
            return NO_ERROR;
        }
        ULONG STDMETHODCALLTYPE AddRef() { return reference_count++; }
        ULONG STDMETHODCALLTYPE Release() { 
            if ( --reference_count == 0 ) delete this;
            return reference_count; 
        }
        HRESULT STDMETHODCALLTYPE foobar() { return NO_ERROR; }
};

// Implementation of the foo2 object
class foo2 : public IFoo2 {
    private:
        DWORD reference_count;
    public:
        foo2() : reference_count(0) { }
        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID * object) {
            *object = NULL;
            if ( riid == IID_IUnknown || riid == __uuidof(IFoo2) ) {
                *object = this;
                this->AddRef(); 
            }
            if ( *object == NULL ) return E_NOINTERFACE;
            return NO_ERROR;
        }
        ULONG STDMETHODCALLTYPE AddRef() { return reference_count++; }
        ULONG STDMETHODCALLTYPE Release() { 
            if ( --reference_count == 0 ) delete this;
            return reference_count; 
        }
        HRESULT STDMETHODCALLTYPE foobar() { return NO_ERROR; }
};

// Implementation of FooClassFactory object
class FooClassFactory : public IFooClassFactory {
    private:
        DWORD reference_count;
    public:
        FooClassFactory() {}
        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID * object) {
            *object = NULL;
            if ( riid == IID_IUnknown || riid == IID_IClassFactory || riid == __uuidof(IFooClassFactory) ) {
                *object = this;
                this->AddRef(); 
            }
            if ( *object == NULL ) return E_NOINTERFACE;
            return NO_ERROR;
        }
        ULONG STDMETHODCALLTYPE AddRef() { return reference_count++; }
        ULONG STDMETHODCALLTYPE Release() { 
            if ( --reference_count == 0 ) delete this;
            return reference_count; 
        }
        HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) {
            if ( pUnkOuter != NULL ) return CLASS_E_NOAGGREGATION;
            if ( riid == __uuidof(IFoo2) || riid == IID_IUnknown ) {
                foo2 * This = new foo2;
                return This->QueryInterface(__uuidof(IFoo2), ppvObject);
            }
            if ( riid == __uuidof(IFoo) ) {
                foo * This = new foo;
                return This->QueryInterface(__uuidof(IFoo), ppvObject);
            }
            return E_NOINTERFACE;
        }
        HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) {
            if ( fLock )
                AddRef();
            else
                Release();
            return NO_ERROR;
        }
};

// Class factory creation
HRESULT CreateClassFactory(PVOID * object) {
    FooClassFactory * This = new FooClassFactory;
    return This->QueryInterface(__uuidof(IFooClassFactory), (PVOID *)object);
}

// main program entry point
int main() {
    IFooClassFactory * foo_factory;
    IFoo * foo_object;
    IFoo2 * foo2_object;
    // Create an IFooClassFactory interface
    HRESULT hr = CreateClassFactory((PVOID *)&foo_factory);
    // Create an instance of the IFoo object
    foo_factory->CreateInstance(NULL, __uuidof(IFoo), (PVOID *)&foo_object);
    foo_factory->CreateInstance(NULL, __uuidof(IFoo2), (PVOID *)&foo2_object);
    foo_object->foobar();
    foo2_object->foobar();
    foo_object->Release();
    foo_object = NULL;
    foo2_object->Release();
    foo2_object = NULL;
    foo_factory->Release();
    foo_factory = NULL;
    return 0;
}



The code above creates an IFooClassFactory object and using its CreateInstance interface, creates an IFoo and IFoo2 interface. The foobar method from each of the two respective interfaces and finally each of the object instances is released. The code then releases the IFooClassFactory object and exits.

Let's take a look more closely at the implementation of the CreateInstance and LockServer methods provided on the IFooClassFactory interface.

CreateInstance method

The first line if ( pUnkOuter != NULL ) return CLASS_E_NOAGGREGATION; is checking to see if the first parameter is a NULL pointer. This first pointer is only used on aggregatable objects which we shall not be covering here so it should always be NULL and if it's not, we return an error to the caller.

The next three lines

    if ( riid == __uuidof(IFoo2) || riid == IID_IUnknown ) {
        foo2 * This = new foo2;
        return This->QueryInterface(__uuidof(IFoo2), ppvObject);
    }



say that if the caller is asking for an IFoo2 interface, or an IUnknown interface, then we should create an new foo2 object, call the created instances' QueryInterface. One very important thing about COM objects is that ALL interfaces that the object supports (and IUnknown is a supported interface as it is from this interface our IFoo2 interface is derived) must be covered. So here if a request is made for an IUnknown interface, we return an IFoo2 interface as default.

The next three lines

    if ( riid == __uuidof(IFoo) ) {
        foo * This = new foo;
        return This->QueryInterface(__uuidof(IFoo), ppvObject);
    }



say that if the caller is asking for an IFoo interface, then we shoudl create a new foo object and call the created instances' QueryInterface.

Finally, the last line return E_NOINTERFACE; says that if the caller is not requesting an IUnknown, IFoo2 or IFoo interface then return an error indicating that the interface is not supported.

LockServer

Oddly enough, the code provided in the example is all that is needed for this function. It simply ensures that the server side does not get removed from memory until it is unlocked. We shall cover this in greater detail much further down the line.

Conclusion

If you have made it this far, and have followed and understood this part of the introduction to COM objects, as well as the previous tutorial, then that is quite fantastic. I suspect however, this tutorial and the previous tutorial have blown every fuse in your mind and sadly, we have not finished yet. In the next tutorial, I am going to introduce you to the magic stuff that makes this technology so amazing.

This post has been edited by Martyn.Rae: 04 April 2010 - 01:33 PM


Is This A Good Question/Topic? 0
  • +

Page 1 of 1