Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C++
Article

A very simple COM server without ATL or MFC

Rate me:
Please Sign up or sign in to vote.
4.30/5 (18 votes)
3 Aug 2000CPOL 260.9K   3.4K   62   48
A step by step guide to write a COM server using C++ without MFC or ATL.

What is it and Why is it!

This is basically a very simple DLL COM server implemented totally in C++ with no support from ATL or MFC and is very easy to write. Writing a COM object this way gave me an insight into the way inproc servers are handled by COM and how Class Factories are created. What I ended up with was a simple framework of classes that can be used to implement fairly basic COM components like Shell Extensions etc, with the whole purpose of publishing this code being to get some feed back from you people....

What to expect

In order to write your own COM object the first thing that we have to do is:

Step One

Write an Interface header file (sample file included in the project) and write methods that you want to implement as shown. A GUID for the object is defined and the interface is given an IID. We need to use this from the client side as shown:

HRESULT hr;
ImyInterface *pmine=(0);
hr = CoCreateInstance(CLSID_Mine,               // CLSID of COM server
                      NULL,          
                      CLSCTX_INPROC_SERVER,     // it is a DLL 
                      __uuidof(ImyInterface),   // the interface IID
                      (void**)&pmine    
                      );

We can also get the CLSID from the registry using CLSIDFromProgId passing it the ProgId of the component.

 // Interface.h
 // GUID of our COM server
 _declspec(selectany) GUID CLSID_Mine = { 0xdc186800,  0x657f,  0x11d4, 
          {      
          0xb0, 
          0xb5,
          0x0,  
          0x50,  
          0xba,  
          0xbf,  
          0xc9,  
          0x4   
          }
        };

// interface definition
// for sample COM server just replace the uuid of interface and its name
// and add new method prototypes here ..
// 
interface __declspec(uuid("F614FB00-6702-11d4-B0B7-0050BABFC904")) 
         ImyInterface : public IUnknown
{ 
  STDMETHOD(Square)(long *pVal)PURE;
  STDMETHOD(Cube)(long *pVal)PURE;
};

The sample interface just exposes two methods Square and Cube both taking a long pointer as parameter.

Step Two

Now we need to provide an implementation of the interface that we have defined, one way to do it is by creating a new class that inherits from interface like:

// this class implements a single interface ImyInterface ...
// 
class CmyInterface : public CComBase<> , 
                     public InterfaceImpl<ImyInterface> 
{
public:
  CmyInterface();
  virtual ~CmyInterface();

  // we however need to write code for queryinterface 
  STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv);

  // ImyInterface methods
  STDMETHOD(Square)(long *pVal);
  STDMETHOD(Cube)(long *pVal);

};

The template class InterfaceImpl<> provides the implementation of reference counting for the interfaces. Here we can inherit from multiple interfaces so that a single COM component can implement more than one interface.

Step Three

Writing Queryinterface and the two interface methods is the only thing left before we finish with the object.

STDMETHODIMP CmyInterface::QueryInterface(REFIID riid,LPVOID *ppv)
{
  *ppv = NULL;
  if(IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,__uuidof(ImyInterface)))
  {
    // since we derive publically from ImyInterface this is a valid typecast
    *ppv = (ImyInterface *) this;  
    
    _AddRef();    // this method is inherited from a base class
    return S_OK;
  }
  return E_NOINTERFACE;
}

STDMETHODIMP CmyInterface::Square(long *pVal)
{
  long value = *pVal;
  *pVal = value * value;
  return S_OK;
}

STDMETHODIMP CmyInterface::Cube(long *pVal)
{
  long value = *pVal;
  *pVal = value * value * value;
  return S_OK;
}

Note that, we are using __uuidof(ImyInterface) to get the interface IID of the interface. This is because we already have associated a uuid with the interface in step One.

Final Step

COM DLLs have to export a function called DllGetClassObject. DllGetClassObject creates a Class Factory for CmyInterface and returns a reference to it. When we call CoCreateInstance for an inproc server, COM creates a class factory for the object by calling DllGetClassObject. The class factory has a method CreateInstance that creates the object and returns references to it.

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
{
    *ppvOut = NULL;
    if (IsEqualIID(rclsid, CLSID_Mine))
    {
       // declare a classfactory for CmyInterface class 
       CClassFactory<CmyInterface> 
       *pcf = new CClassFactory<CmyInterface>; 
       return pcf->QueryInterface(riid,ppvOut);
    }
    return CLASS_E_CLASSNOTAVAILABLE;
}

Here we check to see, if the request is for Class Factory of objects identified by CLSID_Mine and if not, we simply return an error code.

You might be asking where are we creating the actual objects of class CmyInterface , this infact is handled by the template instantiation of CClassFactory<CmyInterface>. Here is what the actual implementation of CClassFatory is:

// Creator class for Singleton class factories this class returns the 
// pointer to the same object for multiple CreateObject requests ..
 
template<class comObj>
class CSingleCreator
{
protected:
  CSingleCreator():m_pObj(0) {};

  comObj *CreateObject()
  {
    if(!m_pObj)
    {
      m_pObj = new comObj;
    }
    return m_pObj;
  }
  comObj * m_pObj;
};

// Creator class for normal class factories this class returns 
// the pointer to a new object for each CreateObject request ..
 
template<class comObj>
class CMultiCreator
{
protected:
  CMultiCreator():m_pObj(0) {};
  comObj *CreateObject()
  {
    return new comObj;
  }
  comObj * m_pObj;
};

// ClassFactory implementation using the classes all around us 
// now the default creator class for classfactory is MultiCreator 
// this class implements IClasFactory interface ....
 
class CClassFactory  : public CComBase<>,
                       public InterfaceImpl<IClassFactory>,
                       public creatorClass 
{
public:
  CClassFactory() {};
  virtual ~CClassFactory() {};

  STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv)
  {
    *ppv = NULL;
    if(IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,IID_IClassFactory))
    {
      *ppv = (IClassFactory *) this;
      _AddRef();   
      return S_OK;
    }
    return E_NOINTERFACE;
  }

  STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, <BR>                              LPVOID *ppvObj)
  {
    *ppvObj = NULL;
    if (pUnkOuter)
        return CLASS_E_NOAGGREGATION;
    m_pObj = CreateObject();  // m_pObj is defined in creatorClass 
    if (!m_pObj)
        return E_OUTOFMEMORY;
    HRESULT hr = m_pObj->QueryInterface(riid, ppvObj);
    if(hr != S_OK)
    {
      delete m_pObj;
    }
    return hr;
  }

  STDMETHODIMP LockServer(BOOL) {  return S_OK; }  // not implemented
};

CreateInstance is called by COM to create an object of the required type, parameter riid is the IID of the interface that is requested and if the object supports, it increments its reference count and returns a reference to itself.

About the Code

The details in this articles are the very brief and many aspects have been omitted. It just describes the bare details of how to implement a COM server from scratch. Having a look at the code gives you an idea of how the sequence works and if you are looking to write a COM server from scratch this may give you an idea of where to start. You may expect bugs in the code but this is because the sole purpose is to convey the ideas. You can modify it to suit your needs if you like.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Pakistan Pakistan
Let a = b ....... (1)
a - b = a - b
a^2 - ab = a^2 - ab
a^2 - ab = a^2 - b^2 (from 1)
a (a - b) = (a + b) (a - b)
a = (a + b) ...... (2)

if a = 1
1 = (1 + 1) (from 1 & 2)
1 = 2 !!

Comments and Discussions

 
QuestionCreate COM Object not success. Pin
thiensy9-Apr-12 18:54
thiensy9-Apr-12 18:54 
Hi you!
I build myserv.dll in VS2010.
Regsvr: myserv.dll success.
but:
CoCreateInstance(CLSID_Mine,NULL, CLSCTX_INPROC_SERVER, __uuidof(ImyInterface)(void**)&pmine ) not success??
Synt
life is our we live our way

QuestionRe: Create COM Object not success. Pin
.Shoaib10-Apr-12 6:12
.Shoaib10-Apr-12 6:12 
AnswerRe: Create COM Object not success. Pin
MotiP18-Apr-12 18:34
MotiP18-Apr-12 18:34 
QuestionCan i use this COM server in VB.net Pin
uks2k630-Nov-11 23:17
uks2k630-Nov-11 23:17 
AnswerRe: Can i use this COM server in VB.net Pin
.Shoaib1-Dec-11 0:27
.Shoaib1-Dec-11 0:27 
JokeWrong proof Pin
Damiendra Buwaneka3-Feb-09 1:18
Damiendra Buwaneka3-Feb-09 1:18 
GeneralRe: Wrong proof Pin
Member 1021183031-Jan-14 21:32
Member 1021183031-Jan-14 21:32 
GeneralOOT: Flaw in your signature Pin
Norman Sasono27-Jul-06 22:19
Norman Sasono27-Jul-06 22:19 
AnswerRe: OOT: Flaw in your signature Pin
.Shoaib8-Aug-06 19:59
.Shoaib8-Aug-06 19:59 
GeneralRe: OOT: Flaw in your signature Pin
rajbow19-Sep-06 1:26
rajbow19-Sep-06 1:26 
GeneralGreat Work, but some bug found. Pin
jung donghun7-Sep-05 19:39
jung donghun7-Sep-05 19:39 
GeneralGreat.... Pin
gavittl21-Aug-05 8:29
gavittl21-Aug-05 8:29 
GeneralMatlab COM Pin
dnqhung20-May-04 18:30
dnqhung20-May-04 18:30 
QuestionWhat kind of project is this Pin
tunafish243-Jan-04 18:42
tunafish243-Jan-04 18:42 
AnswerRe: What kind of project is this Pin
Prakash Nadar19-Jan-04 16:15
Prakash Nadar19-Jan-04 16:15 
Generalcould not initialise COM server Pin
Anonymous9-Dec-03 21:42
Anonymous9-Dec-03 21:42 
GeneralRe: could not initialise COM server Pin
songkiet8-Feb-04 20:34
songkiet8-Feb-04 20:34 
GeneralRe: could not initialise COM server Pin
Member 813948311-Aug-12 5:03
Member 813948311-Aug-12 5:03 
GeneralRe: could not initialise COM server Pin
Member 116368831-May-15 10:23
Member 116368831-May-15 10:23 
GeneralPlug-in for MS Outlook Pin
Atif Bashir30-Jul-03 16:31
Atif Bashir30-Jul-03 16:31 
GeneralRe: Plug-in for MS Outlook Pin
John M. Drescher30-Jul-03 16:40
John M. Drescher30-Jul-03 16:40 
GeneralSome food for COM lovers Pin
suhail197817-Jun-03 2:13
suhail197817-Jun-03 2:13 
Generalcalgonit Pin
calgonit3-Mar-03 23:40
calgonit3-Mar-03 23:40 
Questioncant work?? Pin
William.Zhang18-Dec-02 22:42
William.Zhang18-Dec-02 22:42 
AnswerRe: cant work?? Pin
Yogesh Kshatriya23-Jun-04 3:51
Yogesh Kshatriya23-Jun-04 3:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.