3D PLM Enterprise Architecture

Middleware Abstraction - Object Modeler

Instantiating a Component using its CLSID

Implementing IClassFactory and using CATCreateInstance
Use Case

Abstract

This article shows how to instantiate a CAA V5 component using its CLSID.


What You Will Learn With This Use Case

This use case is intended to show you how to create the CLSID for your CAA V5 component and how client applications can instantiate your component using its CLSID. The component referred to this use case is the CAASysComponent component mentioned in [1]. This component represents an object with two facets, each of them being supported using an interface:

  1. CATICreateInstance to allow the component to be instantiated by client applications using the CATInstantiateComponent global function;
  2. CAAISysMyInterface to print a message on the screen.

Creating these interfaces and their implementations is not described here. You can refer to other articles dealing with this topic [2] [3].

Here we will learn how to allow this component to be instantiated by client applications using the CATCreateInstance global function.

[Top]

The CAASysComponentCreateCLSID Use Case

CAASysComponentCreateCLSID is a use case of the CAASystem.edu framework that illustrates the System framework capabilities.

[Top]

What Does CAASysComponentCreateCLSID Do

This use case shows the steps to follow to create the CLSID of a basic component to enable client applications to instantiate it.

As in use case [1], this component is made of the CAASysComponent main class, of the CAAESysCreateInstanceForComponent and CAAESysMyInterfaceForComponent extension classes.

For our purpose, it is also made of the CAASysComponentFactory class that implements the IClassFactory interface to enable the component creation using its CLSID.

Finally the component's implementation library must define the CATDllGetClassObject entry point.

The main program instantiates this component, retrieves a pointer to the CAAISysMyInterface interface this component implements and use this pointer to call a method.

[Top]

How to Launch CAASysComponentCreateCLSID

You first need to build CAASysComponentCreateCLSID. To do this, you will need to set up the build time environment, then compile all the CAASysComponent*.m modules along with their prerequisites as described in [4]. Launch CAASysComponentCreateCLSID itself.

[Top]

Where to Find the CAASysComponentCreateCLSID Code

The CAASysComponentCreateCLSID use case is made of five modules:

Windows InstallRootDirectory\CAASystem.edu\CAASysComponent*.m
Unix InstallRootDirectory/CAASystem.edu/CAASysComponent*.m

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

These modules are:

  1. CAASysComponentImpl.m that contains the component main class, the extension class that implements CATICreateInstance, the class that implements IClassFactory, and the implementation of CATDllGetClassObject
  2. CAASysComponentCLSID.m that contains the definition of the component CLSID, the corresponding header being located in the PublicInterfaces directory of the CAASystem.edu framework
  3. CAASysComponentInt.m that contains the CAAISysMyInterface interface and its TIE, the interface header being located in the PublicInterfaces directory of the CAASystem.edu framework
  4. CAASysComponentExt.m that contains the extension class that implements CAAISysMyInterface
  5. CAASysComponentCreateCLSID.m that contains the main program that instantiates the component using its CLSID

Some parts of these modules are described in [1]. We only deal here with the new code.

[Top]

Step-by-Step

To create and use the CLSID of the CAASysComponent, there are five main steps:

# Step Where
1 Declare and define the CAASysComponent CLSID PublicInterfaces\CAASysComponentCLSID.h and CAASysComponentCLSID.m\src\CAASysComponentCLSID.cpp
2 Implement the IClassFactory interface CAASysComponent.m\src\CAASysComponentFactory.cpp
3 Implement the CATDllGetClassObject function CAASysComponent.m\src\CAASysGetClassObject.cpp
4 Update the dictionary CAASystem.edu.dico and CAASystem.edu.clsid files in CNext\code\dictionary
5 Instantiate and use the component CAASysComponentCreateCLSID.m\src\CAASysMain.cpp

[Top]

Declare and define the CAASysComponent CLSID

Declaration in the CAASysComponentCLSID.h header file:
// System Framework
#include "IUnknown.h"
	
#ifdef _WINDOWS_SOURCE
#ifdef __CAASysComponentCLSID
#define ExportedByCAASysComponentCLSID __declspec(dllexport)
#else
#define	ExportedByCAASysComponentCLSID __declspec(dllimport)
#endif
#else
#define ExportedByCAASysComponentCLSID
#endif

extern "C" ExportedByCAASysComponentCLSID const CLSID CLSID_CAASysComponent;
      
Definition in the CAASysComponentCLSID.cpp source file:
#include "CAASysComponentCLSID.h"

const CLSID CLSID_CAASysComponent = { /* 876db66d-b22b-435a-8c91-607db2d33663 */
    0x876db66d,
    0xb22b,
    0x435a,
    {0x8c, 0x91, 0x60, 0x7d, 0xb2, 0xd3, 0x36, 0x63}
  };
      

The CLSID of a component is nothing more than a GUID that uniquely identify your component. CLSIDs for components are equivalent to IIDs for interfaces.

The CLSID of a component CAASysComponent is referred to by the symbol CLSID_CAASysComponent which is exported by the CAASysComponentCLSID library.

To be able to use the CLSID of a component, it is sufficient for client applications to include the CLSID declaration header and to link the code with the CLSID library.

[Top]

Implement the IClassFactory interface

Declaration in the CAASysComponentFactory.h header file:
#include "CATBaseUnknown.h" // Needed to derive from CATBaseUnknown

class CAASysComponentFactory : public CATBaseUnknown
{
    // Used in conjunction with CATImplementClass in the .cpp file
    CATDeclareClass;
    
    public:
    
    CAASysComponentFactory();
    virtual ~CAASysComponentFactory();
    
    virtual HRESULT __stdcall CreateInstance(IUnknown * iUnkOuter, const IID &iIid, void ** oObject);
    virtual HRESULT __stdcall LockServer(int iLock);
    
    private:
    
    // Not implemented
    CAASysComponentFactory(const CAASysComponentFactory &);
    // Not implemented
    CAASysComponentFactory & operator = (const CAASysComponentFactory &);
};
      
Definition in the CAASysComponentFactory.cpp source file:
#include "CAASysComponentFactory.h" // This class declaration

#include "iostream.h" // For output
#include "CATErrorDef.h"
#include "CAASysComponent.h" // The component to create

// OM Implementation
CATImplementClass(CAASysComponentFactory, Implementation, CATBaseUnknown, CATNull);

CAASysComponentFactory::CAASysComponentFactory()
{
    cout << "CAASysComponentFactory::CAASysComponentFactory()" << endl;
}

CAASysComponentFactory::~CAASysComponentFactory()
{
    cout << "CAASysComponentFactory::~CAASysComponentFactory()" << endl;
}

// To create the TIE object
#include "TIE_IClassFactory.h"
TIE_IClassFactory( CAASysComponentFactory );

HRESULT __stdcall CAASysComponentFactory::LockServer(int iLock)
{
    return S_OK;
}

HRESULT __stdcall CAASysComponentFactory::CreateInstance(IUnknown * iUnkOuter, const IID &iIid, void ** oObject)
{
    CAASysComponent * pCAASysComponent = new CAASysComponent();
    if(NULL == pCAASysComponent) return E_OUTOFMEMORY;
    
    HRESULT hr = pCAASysComponent->QueryInterface(iIid, oObject);
    
    pCAASysComponent->Release();
    pCAASysComponent = NULL;
    
    return hr;
}
      

The CAASysComponentFactory class implements the IClassFactory interface.

As can be seen, the IClassFactory interface has two methods but only CreateInstance is useful for our purpose, which is to instantiate our component. The actual implementation is very similar to the implementation of the CreateInstance method of the CATICreateInstance interface as described in [1]. The difference here is that a query interface is immediately done to retrieve a pointer to an interface implemented by our component.

[Top]

Implement the CATDllGetClassObject function

// System Framework
#include "IUnknown.h"
#include "CATErrorDef.h"
#include "CATCmpGuid.h"

// This Framework
#include "CAASysComponentFactory.h" // The component factory to create
#include "CAASysComponentCLSID.h" // CLSID declaration of the component

#ifdef _WINDOWS_SOURCE
#define ExportedByCAASysComponentImpl __declspec(dllexport)
#else
#define ExportedByCAASysComponentImpl
#endif

extern "C" HRESULT ExportedByCAASysComponentImpl CATDllGetClassObject(const CLSID & rclsid, const IID & riid, void ** ppv)
{
    HRESULT hr = E_NOTIMPL;
    
    if (CATCmpGuid(&rclsid, &CLSID_CAASysComponent))
    {
        CAASysComponentFactory * pCAASysComponentFactory = new CAASysComponentFactory();
        if(NULL == pCAASysComponentFactory) return E_OUTOFMEMORY;
        
        hr = pCAASysComponentFactory->QueryInterface(riid, ppv);
        
        pCAASysComponentFactory->Release();
        pCAASysComponentFactory = NULL;
    }
    
    return hr;
}
      

Defining the factory for our component is not enough. For our component to be actually instantiable by CLSID in client applications, the library where it is defined must implement the function CATDllGetClassObject which will be the real entry point to the component.

What CATDllGetClassObject is doing ?

Its purpose is just to instantiate the component factory and to return a pointer to the IClassFactory interface that the component factory implements.

Note that a comparison on the CAASysComponent CLSID is made at the beginning to ensure we create the right factory for the component.

[Top]

Updating the Dictionary

CAASystem.edu.dico extract:
...
CAASysComponentFactory IClassFactory  libCAASysComponentImpl
...

The interface dictionary declares that the CAASysComponentFactory class implements the IClassFactory interface and that the code to load into memory to use this interface is located in the libCAASysComponentImpl shared library or DLL.

CAASystem.edu.clsid:

...
{876db66d-b22b-435a-8c91-607db2d33663} CAASysComponent CAASysComponentImpl
...

The component dictionary links together the CLSID, the name of the component CAASysComponent, and the shared library or DLL where the entry point CATDllGetClassObject is defined (which is the component implementation library, CAASysComponentImpl).

Note that the prefix lib is omitted in the library name.

Top]

Instantiating and Using the Component

// System Framework
#include "CATErrorDef.h"              // For the FAILED macro
#include "CATCreateInstance.h"        // For the global function to create the component by CLSID

// This componennt Framework
#include "CAAISysMyInterface.h"       // An interface implemented by the component
#include "CAASysComponentCLSID.h"     // For the CLSID of the component

// C++ standard library    
#include      // To display traces

int main()
{

  cout << "The CAASysComponentCreateCLSID Sample begins ....."<< endl;

 
  // -------------------------------------------------------------------------------
  // Creates the component and retrieves a CAAISysMyInterface interface pointer
  // -------------------------------------------------------------------------------

  CAAISysMyInterface * piSysMyInterfaceOnComponent = NULL; 
  HRESULT rc = ::CATCreateInstance( CLSID_CAASysComponent, NULL, 0, 
                                         IID_CAAISysMyInterface,
                                         (void**)&piSysMyInterfaceOnComponent);   
                                          
  if ( FAILED (rc) )
  {
       cout << " Problem in the component Creation"<< endl;
       return 1 ;
  }

  //-----------------------------------------------------------------------
  //The component is created, and we can use the returned interface pointer 
  //-----------------------------------------------------------------------
  piSysMyInterfaceOnComponent->Print();

  //-----------------------------
  // Pointer no any longer needed
  //-----------------------------
  piSysMyInterfaceOnComponent->Release();
  piSysMyInterfaceOnComponent = NULL;


  cout << endl << "The CAASysComponentCreateCLSID Sample is finished."<< endl << endl ;

  return 0 ;
}
      

The CAASysComponent component is instantiated using the CATCreateInstance global function to which the following parameters should be passed:

CLSID_CAASysComponent The component CLSID, that uniquely identifies the component
NULL Must always be NULL
0 Must always be 0
IID_CAAISysMyInterface The IID of the interface with which the client application wants to handle the component and to which a pointer is asked
piSysMyInterfaceOnComponent The pointer to that interface

Once the component is instantiated and handled using a pointer to the requested interface, the client application can go on using the component. No link is necessary between the client application and the component code. Only the library defining the component CLSID is needed for linkage purpose (CAASysComponentCLSID). CATCreateInstance and the implemented interfaces isolates the two codes and are used as a contract between them to ensure that they will go on running as planned, and that modification to the component's code will not affect the client application and will ensure run time compatibility.

[Top]


In Short

This use case shows how to create a factory for a component by using its CLSID. The component factory class implements the IClassFactory interface and the entry point function CATDllGetClassObject is implemented in the component library to instantiate the component factory class. The component dictionary declares the correspondence between the component CLSID, the component name, and the component implementation library. CATCreateInstance is used to instantiate the component knowing its CLSID and returns a pointer to the interface requested by the client application.

[Top]


References

[1] Creating and Instantiating a Component
[2] Creating Components
[3] Creating Interfaces
[4] Building and Launching a CAA V5 Use Case
[Top]

History

Version: 1 [May 2003] Document created
[Top]

Copyright © 1994-2003, Dassault Systèmes. All rights reserved.