Created
May 20, 2014 02:48
-
-
Save kasajian/97d17c3c7fa16dccf111 to your computer and use it in GitHub Desktop.
Creating a COM Object in plain C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment