Creating a COM Object in plain C++
#ifndef __CCOM_H__
#define __CCOM_H__
//------------------------------------------------------------------------------
// CLASS CFactory
//------------------------------------------------------------------------------
class CFactory : public IClassFactory
{
public:
CFactory( const CLSID& clsid );
// IUnknown methods
virtual HRESULT __stdcall QueryInterface( const IID& riid, void** ppv );
virtual ULONG __stdcall AddRef( void );
virtual ULONG __stdcall Release( void );
// IClassFactory methods
virtual HRESULT __stdcall CreateInstance( IUnknown* punkOuter, const IID& riid, void** ppv );
virtual HRESULT __stdcall LockServer( BOOL fLock );
private:
ULONG fReferenceCount;
CLSID fClsid;
}; // class CFactory
//------------------------------------------------------------------------------
// CLASS CMath
//------------------------------------------------------------------------------
class CMath : public IDispatch
{
public:
CMath(): fReferenceCount( 0 ) {}
// IUnknown methods
virtual HRESULT __stdcall QueryInterface( const IID& riid, void** ppv );
virtual ULONG __stdcall AddRef( void );
virtual ULONG __stdcall Release( void );
// IDispatch methods
virtual HRESULT __stdcall GetTypeInfoCount( UINT* );
virtual HRESULT __stdcall GetTypeInfo( UINT, LCID, ITypeInfo** );
virtual HRESULT __stdcall GetIDsOfNames( REFIID, OLECHAR**, UINT, LCID, DISPID* );
virtual HRESULT __stdcall Invoke( DISPID, REFIID, LCID, USHORT, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT* );
private:
ULONG fReferenceCount;
}; // class CMath
#endif // __CCOM_H__
#include <windows.h>
#include "ccom.h"
// In order to use from VBScript, you need to place the progID in the registry so
// that it can be used to obtain the CLSID of this class.
// VB script
/*
DIM X
DIM Y
SET X = CREATEOBJECT( "BrlsMath.Math" )
Y = X.ADD( 5, 6 )
MSGBOX Y
SET X = NOTHING
*/
// ccom.reg file:
/*
REGEDIT
; This .REG file may be used by your SETUP program.
HKEY_CLASSES_ROOT\BrlsMath.Math = Borealis Sample Math class
HKEY_CLASSES_ROOT\BrlsMath.Math\CLSID = {EADAD891-D328-11d1-BEAA-00A02481FB8E}
HKEY_CLASSES_ROOT\CLSID\{0218BDBC-D31A-11D1-BEAA-00A02481FB8E} = Borealis Sample Math class
HKEY_CLASSES_ROOT\CLSID\{0218BDBC-D31A-11D1-BEAA-00A02481FB8E}\ProgId = BrlsMath.Math
*/
// {EADAD891-D328-11d1-BEAA-00A02481FB8E}
static const GUID CLSID_Math =
{ 0xeadad891, 0xd328, 0x11d1, { 0xbe, 0xaa, 0x0, 0xa0, 0x24, 0x81, 0xfb, 0x8e } };
#define kMemberAdd 1
#define kMemberSubtract 2
//========================================================================================
// CLASS CFactory
//========================================================================================
//------------------------------------------------------------------------------
// CFactory::CFactory
//------------------------------------------------------------------------------
CFactory::CFactory( const CLSID& clsid )
: fReferenceCount( 1 ),
fClsid( clsid )
{
} // CFactory::CFactory
//------------------------------------------------------------------------------
// CFactory::QueryInterface
// Implementation of IUnknown method
//------------------------------------------------------------------------------
HRESULT CFactory::QueryInterface( const IID& riid, void ** ppv )
{
if ( IsEqualIID( riid, IID_IUnknown ) ||
IsEqualIID( riid, IID_IClassFactory ) )
{
AddRef();
*ppv = this;
return NOERROR;
}
*ppv = NULL;
return ResultFromScode( E_NOINTERFACE );
} // CFactory::QueryInterface
//------------------------------------------------------------------------------
// CFactory::AddRef
// Implementation of IUnknown method
//------------------------------------------------------------------------------
ULONG CFactory::AddRef( )
{
return ++fReferenceCount;
} // CFactory::AddRef
//------------------------------------------------------------------------------
// CFactory::Release
// Implementation of IUnknown method
//------------------------------------------------------------------------------
ULONG CFactory::Release()
{
if( 0 == --fReferenceCount )
{
delete this;
return 0;
}
return fReferenceCount;
} // CFactory::Release()
//------------------------------------------------------------------------------
// CFactory::CreateInstance
// Implementation of IClassFactory method.
//------------------------------------------------------------------------------
HRESULT CFactory::CreateInstance( IUnknown* punkOuter,
const IID& riid,
void** ppv)
{
HRESULT hresult = E_NOINTERFACE;
*ppv = NULL;
if ( CLSID_Math == fClsid )
{
CMath* math = new CMath;
hresult = math->QueryInterface( riid, ppv );
if ( FAILED( hresult ) )
math->Release( );
}
return hresult;
punkOuter;
} // CFactory::CreateInstance
//------------------------------------------------------------------------------
// CFactory::LockServer
// Implementation of IClassFactory method.
//------------------------------------------------------------------------------
HRESULT CFactory::LockServer( BOOL fLock )
{
return NOERROR;
fLock;
} // CFactory::LockServer
//------------------------------------------------------------------------------
// CMath::QueryInterface
// IUnknown method
// Implementation of IUnknown method
//------------------------------------------------------------------------------
HRESULT CMath::QueryInterface( const IID& riid, void** ppv )
{
*ppv = NULL;
if ( IsEqualIID( riid, IID_IUnknown ) ||
IsEqualIID( riid, IID_IDispatch ) )
{
this->AddRef();
*ppv = (IDispatch*) this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
} // CMath::QueryInterface
//------------------------------------------------------------------------------
// CMath::AddRef
// IUnknown method
// Implementation of IUnknown method
//------------------------------------------------------------------------------
ULONG CMath::AddRef( )
{
return ++fReferenceCount;
} // CMath::AddRef
//------------------------------------------------------------------------------
// CMath::Release
// IUnknown method
// Implementation of IUnknown method
//------------------------------------------------------------------------------
ULONG CMath::Release()
{
if( 0 == --fReferenceCount )
{
delete this;
return 0;
}
return fReferenceCount;
} // CMath::Release()
//------------------------------------------------------------------------------
// CMath::GetTypeInfoCount
// IDispatch method
// Returns the number of type information (ITypeInfo) interfaces
// that the object provides (0 or 1).
//------------------------------------------------------------------------------
HRESULT CMath::GetTypeInfoCount( UINT* pctInfo )
{
// We don't have a type info.
*pctInfo=0;
return S_OK;
} // CMath::GetTypeInfoCount
//------------------------------------------------------------------------------
// CMath::GetTypeInfo
// IDispatch method
// Retrieves type information for the automation interface.
//------------------------------------------------------------------------------
HRESULT CMath::GetTypeInfo(UINT, LCID, ITypeInfo** pptInfo)
{
// Since we don't have a type info, nothing to return.
*pptInfo = NULL;
return E_NOTIMPL;
} // CMath::GetTypeInfo
//------------------------------------------------------------------------------
// CMath::GetIDsOfNames
// IDispatch method
// Returns the IDs corresponding to given named in our dispatch
// interface.
//------------------------------------------------------------------------------
HRESULT CMath::GetIDsOfNames( REFIID, OLECHAR** rgszNames, UINT cNames, LCID, DISPID* rgDispID )
{
if ( 1 == cNames )
{
if ( 0 == lstrcmpiW( *rgszNames, L"Add" ) )
{
*rgDispID = kMemberAdd;
return S_OK;
}
else if ( 0 == lstrcmpiW( *rgszNames, L"Subtract" ) )
{
*rgDispID = kMemberSubtract;
return S_OK;
}
}
return DISP_E_UNKNOWNNAME;
} // CMath::GetIDsOfNames
//------------------------------------------------------------------------------
// CMath::Invoke
// IDispatch method
// Calls a method in the dispatch interface or manipulates a
// property.
//------------------------------------------------------------------------------
HRESULT CMath::Invoke( DISPID dispIDMember, REFIID, LCID, USHORT wFlags, DISPPARAMS* dispParams, VARIANT* methodRetVal, EXCEPINFO*, UINT* errArg )
{
HRESULT hresult;
VARIANT arg1;
VARIANT arg2;
// If there's not return variant, use our own, which should always be the case, really.
if ( NULL == methodRetVal )
return E_NOTIMPL;
VariantInit( methodRetVal );
// We only support property gets. So bail otherwise.
if ( DISPATCH_METHOD & wFlags )
{
switch ( dispIDMember )
{
case kMemberAdd:
::VariantInit( &arg1 );
::VariantInit( &arg2 );
hresult = ::DispGetParam( dispParams, dispParams->cArgs - 1, VT_R8, &arg1, errArg );
hresult = ::DispGetParam( dispParams, dispParams->cArgs - 2, VT_R8, &arg2, errArg );
if ( SUCCEEDED( hresult ) )
{
V_VT( methodRetVal ) = VT_R8;
V_R8( methodRetVal ) = arg1.dblVal + arg2.dblVal;
}
::VariantClear( &arg1 );
::VariantClear( &arg2 );
break;
case kMemberSubtract:
::VariantInit( &arg1 );
::VariantInit( &arg2 );
hresult = ::DispGetParam( dispParams, dispParams->cArgs - 1, VT_R8, &arg1, errArg );
hresult = ::DispGetParam( dispParams, dispParams->cArgs - 2, VT_R8, &arg2, errArg );
if ( SUCCEEDED( hresult ) )
{
V_VT( methodRetVal ) = VT_R8;
V_R8( methodRetVal ) = arg1.dblVal - arg2.dblVal;
}
::VariantClear( &arg1 );
::VariantClear( &arg2 );
break;
default:
hresult = DISP_E_MEMBERNOTFOUND;
break;
}
}
else
{
hresult = DISP_E_MEMBERNOTFOUND;
}
return hresult;
} // CMath::Invoke
void main( void )
{
DWORD factoryHandle;
HRESULT hresult;
CFactory* classFactory;
hresult = CoInitialize( NULL );
if ( SUCCEEDED( hresult ) )
{
classFactory = new CFactory( CLSID_Math );
hresult = CoRegisterClassObject( CLSID_Math,
classFactory,
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&factoryHandle );
if ( SUCCEEDED( hresult ) )
{
MessageBox( 0, "ccom", "", 0 );
CoRevokeClassObject( factoryHandle );
}
classFactory->Release( );
CoUninitialize( );
}
} // main