Implementing COM Objects

Preview:

DESCRIPTION

Implementing COM Objects. 主講人:虞台文. Content. Types of COM Servers Objects with Single interface Example  Enumerators Objects with Multiple interfaces Example  Personal Account Server Modules of COM Class Factory & IClassFactory Example  Simple Object Self-Registration - PowerPoint PPT Presentation

Citation preview

Implementing COM Objects

主講人:虞台文

Content

Types of COM Servers Objects with Single interface

– Example Enumerators Objects with Multiple interfaces

– Example Personal Account Server Modules of COM Class Factory & IClassFactory Example Simple Object Self-Registration InProcess Severs by MFC

OLEObject Linking & Embedding

Types of

COM Servers

Using COM Object

ClientClient

COMLibrary

COMLibrary

ServerServer

Object

Create object of a CLSID

CoCreateInstance()

Locate implementation, and load or launch server

Get object interface pointer, and return to

Client

Call interface members

Where is the server located?

ClientClient

COMLibrary

COMLibrary

ServerServer

Object

Create object of a CLSID

CoCreateInstance()

Locate implementation, and load or launch server

Get object interface pointer, and return to

Client

Call interface members

Server Types

Client Process

ClientClient

In-processserver

In-processserver

In-processobject

COMCOM

Localobjectproxy

Remoteobjectproxy

Local server process

Local serverLocal server

Localobject

COMCOM

Stub

Remote server process

COMCOM

Stub

Remote MachineRPC

RPCRemote server

Remote server

Remoteobject

OLEObject Linking & Embedding

Objects with Single Interface

Template of Enumerators

template <class ELT_T> interface IEnum : IUnknown

{

virtual HRESULT Next(ULONG celt, ELT_T *rgelt, ULONG *pceltFetched)=0;

virtual HRESULT Skip(ULONG celt)=0;

virtual HRESULT Reset(void)=0;

virtual HRESULT Clone(IEnum<ELT_T> ** ppEnum)=0;

};

template <class ELT_T> interface IEnum : IUnknown

{

virtual HRESULT Next(ULONG celt, ELT_T *rgelt, ULONG *pceltFetched)=0;

virtual HRESULT Skip(ULONG celt)=0;

virtual HRESULT Reset(void)=0;

virtual HRESULT Clone(IEnum<ELT_T> ** ppEnum)=0;

};

IEnumXxx

Example: Enumerate Rectangles

Example: Enumerate Rectangles

Example: Enumerate Rectangles

IEnumRECT// IEmnuRect.h#if !defined(IEnumRECT_HEARDER)#define IEnumRECT_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IEnumRECT

DECLARE_INTERFACE_(IEnumRECT, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IEnumRECT methods STDMETHOD(Next)(THIS_ DWORD, LPRECT, LPDWORD) PURE; STDMETHOD(Skip)(THIS_ DWORD) PURE; STDMETHOD(Reset)(THIS) PURE; STDMETHOD(Clone)(THIS_ IEnumRECT **) PURE;};

// {6E699FBF-5ED3-44f2-A547-1481C54E130A}DEFINE_GUID(IID_IEnumRECT, 0x6e699fbf, 0x5ed3, 0x44f2, 0xa5, 0x47, 0x14, 0x81, 0xc5, 0x4e, 0x13, 0xa);

typedef IEnumRECT * LPENUMRECT;

#endif // !defined(IEnumRECT_HEARDER)

// IEmnuRect.h#if !defined(IEnumRECT_HEARDER)#define IEnumRECT_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IEnumRECT

DECLARE_INTERFACE_(IEnumRECT, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IEnumRECT methods STDMETHOD(Next)(THIS_ DWORD, LPRECT, LPDWORD) PURE; STDMETHOD(Skip)(THIS_ DWORD) PURE; STDMETHOD(Reset)(THIS) PURE; STDMETHOD(Clone)(THIS_ IEnumRECT **) PURE;};

// {6E699FBF-5ED3-44f2-A547-1481C54E130A}DEFINE_GUID(IID_IEnumRECT, 0x6e699fbf, 0x5ed3, 0x44f2, 0xa5, 0x47, 0x14, 0x81, 0xc5, 0x4e, 0x13, 0xa);

typedef IEnumRECT * LPENUMRECT;

#endif // !defined(IEnumRECT_HEARDER)

CEnumRect// EnumRect.cpp//.....................................#include <afxtempl.h>#include "IEnumRect.h"

class CEnumRect : public IEnumRECT{private: DWORD m_cRef; //Reference count DWORD m_iCur; //Current enum position CArray<RECT, RECT> m_rects; //RECTS we enumerate

public: CEnumRect(CArray<RECT, RECT>& rects); virtual ~CEnumRect();

//IUnknown members STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void);

//IEnumRECT members STDMETHODIMP Next(ULONG, LPRECT, ULONG *); STDMETHODIMP Skip(ULONG); STDMETHODIMP Reset(void); STDMETHODIMP Clone(LPENUMRECT *);};//.....................................

// EnumRect.cpp//.....................................#include <afxtempl.h>#include "IEnumRect.h"

class CEnumRect : public IEnumRECT{private: DWORD m_cRef; //Reference count DWORD m_iCur; //Current enum position CArray<RECT, RECT> m_rects; //RECTS we enumerate

public: CEnumRect(CArray<RECT, RECT>& rects); virtual ~CEnumRect();

//IUnknown members STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void);

//IEnumRECT members STDMETHODIMP Next(ULONG, LPRECT, ULONG *); STDMETHODIMP Skip(ULONG); STDMETHODIMP Reset(void); STDMETHODIMP Clone(LPENUMRECT *);};//.....................................

Constructor/Destructor

CEnumRect::CEnumRect(CArray<RECT, RECT>& rects){ m_rects.Copy(rects); //Ref counts always start at zero m_cRef=0;

//Current pointer is the first element m_iCur=0;}

CEnumRect::~CEnumRect(void){}

CEnumRect::CEnumRect(CArray<RECT, RECT>& rects){ m_rects.Copy(rects); //Ref counts always start at zero m_cRef=0;

//Current pointer is the first element m_iCur=0;}

CEnumRect::~CEnumRect(void){}

CEnumRect::QueryInterface

STDMETHODIMP CEnumRect::QueryInterface(REFIID riid, void** ppv){ //Always NULL the out-parameters *ppv=NULL;

// No explicit typecast necessary since we singly derive // from IEnumRECT. if (IID_IUnknown==riid || IID_IEnumRECT==riid) *ppv= this; // == (LPUNKNOWN) this;

if (NULL==*ppv) return ResultFromScode(E_NOINTERFACE);

//AddRef any interface we'll return. ((LPUNKNOWN)*ppv)->AddRef();

return NOERROR;}

STDMETHODIMP CEnumRect::QueryInterface(REFIID riid, void** ppv){ //Always NULL the out-parameters *ppv=NULL;

// No explicit typecast necessary since we singly derive // from IEnumRECT. if (IID_IUnknown==riid || IID_IEnumRECT==riid) *ppv= this; // == (LPUNKNOWN) this;

if (NULL==*ppv) return ResultFromScode(E_NOINTERFACE);

//AddRef any interface we'll return. ((LPUNKNOWN)*ppv)->AddRef();

return NOERROR;}

CEnumRect::AddRef, Release

STDMETHODIMP CEnumRect::AddRef(void){ return ++m_cRef;}

STDMETHODIMP_(ULONG) CEnumRect::Release(void){ if (0 != --m_cRef) return m_cRef; delete this; return 0;}

STDMETHODIMP CEnumRect::AddRef(void){ return ++m_cRef;}

STDMETHODIMP_(ULONG) CEnumRect::Release(void){ if (0 != --m_cRef) return m_cRef; delete this; return 0;}

Exercise

1. Implementing objects with interfaces IEnumSentence and and IEnumWord for enumerating the sentences and words from a text file.

OLEObject Linking & Embedding

Objects with Multiple Interfaces

Three Methods

Interface Implementations

Contained Interface Classes

Multiple Inheritance

Example: Personal Account

PersonalAccount

IUnknown

IBanking

IPettyCash

IBanking and IPettyCash// Account.h#if !defined(IBanking_IPettyCash_HEARDER)#define IBanking_IPettyCash_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IBanking

DECLARE_INTERFACE_(IBanking, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IBanking methods STDMETHOD(Deposit)(THIS_ UINT) PURE; STDMETHOD(Withdraw)(THIS_ UINT) PURE; STDMETHOD(Balance)(THIS_ UINT *) PURE;};

// {8B5D2FC3-5633-423e-B846-4315F10F7C4A}DEFINE_GUID(IID_IBanking, 0x8b5d2fc3, 0x5633, 0x423e, 0xb8, 0x46, 0x43, 0x15, 0xf1, 0xf, 0x7c, 0x4a);

typedef IBanking * LPBANKING;

// Account.h#if !defined(IBanking_IPettyCash_HEARDER)#define IBanking_IPettyCash_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IBanking

DECLARE_INTERFACE_(IBanking, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IBanking methods STDMETHOD(Deposit)(THIS_ UINT) PURE; STDMETHOD(Withdraw)(THIS_ UINT) PURE; STDMETHOD(Balance)(THIS_ UINT *) PURE;};

// {8B5D2FC3-5633-423e-B846-4315F10F7C4A}DEFINE_GUID(IID_IBanking, 0x8b5d2fc3, 0x5633, 0x423e, 0xb8, 0x46, 0x43, 0x15, 0xf1, 0xf, 0x7c, 0x4a);

typedef IBanking * LPBANKING;

IBanking and IPettyCash// Account.h#if !defined(IBanking_IPettyCash_HEARDER)#define IBanking_IPettyCash_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IBanking

DECLARE_INTERFACE_(IBanking, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IBanking methods STDMETHOD(Deposit)(THIS_ UINT) PURE; STDMETHOD(Withdraw)(THIS_ UINT) PURE; STDMETHOD(Balance)(THIS_ UINT *) PURE;};

// {8B5D2FC3-5633-423e-B846-4315F10F7C4A}DEFINE_GUID(IID_IBanking, 0x8b5d2fc3, 0x5633, 0x423e, 0xb8, 0x46, 0x43, 0x15, 0xf1, 0xf, 0x7c, 0x4a);

typedef IBanking * LPBANKING;

// Account.h#if !defined(IBanking_IPettyCash_HEARDER)#define IBanking_IPettyCash_HEARDER

#include <objbase.h>#undef INTERFACE#define INTERFACE IBanking

DECLARE_INTERFACE_(IBanking, IUnknown){ // IUnknown methods STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // IBanking methods STDMETHOD(Deposit)(THIS_ UINT) PURE; STDMETHOD(Withdraw)(THIS_ UINT) PURE; STDMETHOD(Balance)(THIS_ UINT *) PURE;};

// {8B5D2FC3-5633-423e-B846-4315F10F7C4A}DEFINE_GUID(IID_IBanking, 0x8b5d2fc3, 0x5633, 0x423e, 0xb8, 0x46, 0x43, 0x15, 0xf1, 0xf, 0x7c, 0x4a);

typedef IBanking * LPBANKING;

#undef INTERFACE#define INTERFACE IPettyCash

DECLARE_INTERFACE_(IPettyCash, IUnknown){

// IUnknown methodsSTDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE;STDMETHOD_(ULONG, AddRef)(THIS) PURE;STDMETHOD_(ULONG, Release)(THIS) PURE;// IPettyCash methodsSTDMETHOD(Income)(THIS_ UINT) PURE;STDMETHOD(Pay)(THIS_ UINT) PURE;STDMETHOD(Cash)(THIS_ UINT *) PURE;

};

// {7DCD4D1B-085E-40a7-93FE-4123E6F4C726}DEFINE_GUID(IID_IPettyCash, 0x7dcd4d1b, 0x85e, 0x40a7, 0x93, 0xfe, 0x41, 0x23, 0xe6, 0xf4, 0xc7, 0x26);

typedef IPettyCash * LPPETTYCASH;

#endif // !defined(IBanking_IPettyCash_HEARDER)

#undef INTERFACE#define INTERFACE IPettyCash

DECLARE_INTERFACE_(IPettyCash, IUnknown){

// IUnknown methodsSTDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE;STDMETHOD_(ULONG, AddRef)(THIS) PURE;STDMETHOD_(ULONG, Release)(THIS) PURE;// IPettyCash methodsSTDMETHOD(Income)(THIS_ UINT) PURE;STDMETHOD(Pay)(THIS_ UINT) PURE;STDMETHOD(Cash)(THIS_ UINT *) PURE;

};

// {7DCD4D1B-085E-40a7-93FE-4123E6F4C726}DEFINE_GUID(IID_IPettyCash, 0x7dcd4d1b, 0x85e, 0x40a7, 0x93, 0xfe, 0x41, 0x23, 0xe6, 0xf4, 0xc7, 0x26);

typedef IPettyCash * LPPETTYCASH;

#endif // !defined(IBanking_IPettyCash_HEARDER)

Three Methods

Interface Implementations

Contained Interface Classes

Multiple Inheritance

Exercise

2. Define interfaces for an object which manages personal data used in usual life, e.g., personal information and address book. You also need an interface (e.g., IPersistFile) to access the information from a file.

3. Implement the personal-data object including the interfaces you defined using the three methods described in this lecture.

4. Write an MFC application using the personal-data object.

OLEObject Linking & Embedding

Server Modules of

COM

The Generic Structure of a Server Module

ObjectObject interfaces

(as many as desired)

Class factory:Creates objects

Registration

Sever module

IClassFactory(2)

Exposure forClass factory

Unloadingmechanism

Implementation differs between DLL and EXE servers.

Implementation can be independent of execution context.

Registry Entries

In-process servers: InprocServer32=<path to DLL>

Object handlers: InprocHandler32=<path to DLL>

Local servers: LocalServer32=<path to EXE>

Self-Registration

DLL Servers– DllRegisterServer– DllUnregisterServer

EXE servers Command arguments– /RegServer – /UnregServer

Server Emulation

\

CLSID

{42754580-16b7-11ce-80eb-00aa003d7352} = Original Component

TreatAs = {6fa820f0-2e48-11ce-80eb-00aa003d7352}

AutoTreatAs = {6fa820f0-2e48-11ce-80eb-00aa003d7352}

InprocServer32 = c:\older\original.dll

{6fa820f0-2e48-11ce-80eb-00aa003d7352} = New Emulating Component

InprocServer32 = c:\newer\emulator.dll

\

CLSID

{42754580-16b7-11ce-80eb-00aa003d7352} = Original Component

TreatAs = {6fa820f0-2e48-11ce-80eb-00aa003d7352}

AutoTreatAs = {6fa820f0-2e48-11ce-80eb-00aa003d7352}

InprocServer32 = c:\older\original.dll

{6fa820f0-2e48-11ce-80eb-00aa003d7352} = New Emulating Component

InprocServer32 = c:\newer\emulator.dll

Some API’s

CoGetClassObject

CoCreateInstance(Ex)

CoGetTreatAsClass

CoTreatAsClass

Exercises

5. Read the APIs for server emulations.

6. Lookup system registry to find some entries with TreatAs and AutoTreatAs keys.

OLEObject Linking & Embedding

Class Factory & I

ClassFactory

ServerServer

Class factory(an object)

The Class-Factory Object

ObjectFactory returnsNew interfacePointer to client

IClassFactory-::CreateInstance

Factory manufacturesobject.

ClientClient

IClassFactory

interface IClassFactory : IUnknown

{

HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid,

void **ppv);

HRESULT LockServer(BOOL fLock);

};

interface IClassFactory : IUnknown

{

HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid,

void **ppv);

HRESULT LockServer(BOOL fLock);

};

Licensing with IClassFactory2

interface IClassFactory2 : IClassFactory

{

HRESULT GetLicInfo(LPLICINFO pLicInfo);

HRESULT RequestLicKey(DWORD dwResrved, BSTR FAR* pbstrKey);

HRESULT CreateInstanceLic(IUnknown *pUnkOuter,

IUnknown *pUnkReserved, REFIID riid, BSTR bstrKey,

void **ppvObject);

};

interface IClassFactory2 : IClassFactory

{

HRESULT GetLicInfo(LPLICINFO pLicInfo);

HRESULT RequestLicKey(DWORD dwResrved, BSTR FAR* pbstrKey);

HRESULT CreateInstanceLic(IUnknown *pUnkOuter,

IUnknown *pUnkReserved, REFIID riid, BSTR bstrKey,

void **ppvObject);

};

Exposing the Class Factory In-Process Server

Implement DllGetClassObject

Implement DllCanUnloadNow

STDAPI DllGetClassObject(REFCLSID rclsid,

REFIID riid,

void **ppv);

STDAPI DllGetClassObject(REFCLSID rclsid,

REFIID riid,

void **ppv);

STDAPI DllCanUnloadNow(void);STDAPI DllCanUnloadNow(void);

Exposing the Class Factory Local Server

CoRegisterClassObject

CoRevokeClassObject

HRESULT CoRevokeClassObject(DWORD dwRegister);HRESULT CoRevokeClassObject(DWORD dwRegister);

STDAPI CoRegisterClassObject(

REFCLSID rclsid,

IUnknown * pUnk,

DWORD dwClsContext,

DWORD flags,

LPDWORD lpdwRegister

);

STDAPI CoRegisterClassObject(

REFCLSID rclsid,

IUnknown * pUnk,

DWORD dwClsContext,

DWORD flags,

LPDWORD lpdwRegister

);

In-Process-Server Creation

Local-Server Creation

Create Multiple COM Objects

Step1. Get IClassFactory by

Step2. Call IClassFactory::CreateInstance(…) a number of time if multiple objects are neededStep3. Call IClassFactory::Release().

STDAPI CoGetClassObject(

REFCLSID rclsid, //CLSID associated with the class object

DWORD dwClsContext, //Context for running executable code

COSERVERINFO * pServerInfo, //Pointer to machine on which the object is to

// be instantiated

REFIID riid, //Reference to the identifier of the interface

LPVOID * ppv //Address of output variable that receives the

// interface pointer requested in riid

);

STDAPI CoGetClassObject(

REFCLSID rclsid, //CLSID associated with the class object

DWORD dwClsContext, //Context for running executable code

COSERVERINFO * pServerInfo, //Pointer to machine on which the object is to

// be instantiated

REFIID riid, //Reference to the identifier of the interface

LPVOID * ppv //Address of output variable that receives the

// interface pointer requested in riid

);

Create Single COM Objects

STDAPI CoCreateInstance(

REFCLSID rclsid, //Class identifier (CLSID) of the object

LPUNKNOWN pUnkOuter, //Pointer to controlling IUnknown

DWORD dwClsContext, //Context for running executable code

REFIID riid, //Reference to the identifier of the interface

LPVOID * ppv //Address of output variable that receives

// the interface pointer requested in riid

);

STDAPI CoCreateInstance(

REFCLSID rclsid, //Class identifier (CLSID) of the object

LPUNKNOWN pUnkOuter, //Pointer to controlling IUnknown

DWORD dwClsContext, //Context for running executable code

REFIID riid, //Reference to the identifier of the interface

LPVOID * ppv //Address of output variable that receives

// the interface pointer requested in riid

);

CoGetClassObject() vs. CoCreateInstance()

STDAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwContext, REFIID iid, void **ppv){ HRESULT hr; IClassFactory *pCF;

*ppv=NULL;

hr=CoGetClassObject(rclsid, dwContext, NULL, IID_IClassFactory, (void **) &pCF);

if (FAILED(hr)) return hr;

hr=pCF->CreateInstance(pUnkOuter, iid, ppv);

pCF->Release();

return hr;}

STDAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwContext, REFIID iid, void **ppv){ HRESULT hr; IClassFactory *pCF;

*ppv=NULL;

hr=CoGetClassObject(rclsid, dwContext, NULL, IID_IClassFactory, (void **) &pCF);

if (FAILED(hr)) return hr;

hr=pCF->CreateInstance(pUnkOuter, iid, ppv);

pCF->Release();

return hr;}

OLEObject Linking & Embedding

Example

Simple Object

Example: Simple Object In-Process Sever

Exercises

7. The above example create COM object using CoCreateInstance(). Modify it by using class factory.

8. Modify the server of the above example so that it can create multiple classes of COM object.

9. Code the problem in Exercise 3 as an in-process server, and write an MFC application to use the object.

OLEObject Linking & Embedding

Self-Registration

Some Registry Functions

RegCreateKey(Ex) RegSetValue(Ex) RegCloseKey RegOpenKey(Ex) RegEnumKey(Ex) RegEnumValue RegQueryInfoKey RegDeleteKey

RegSvr32.EXE

DEF File

;DSimpleObject.def : 聲明動態庫 DLL 的模組參數 .

LIBRARY DSimpleObjectDESCRIPTION ' 我的第一個純 C++ COM 對象 '

EXPORTS DllRegisterServer PRIVATE ; COM server registration DllUnregisterServer PRIVATE ; COM server deregistration DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE

;DSimpleObject.def : 聲明動態庫 DLL 的模組參數 .

LIBRARY DSimpleObjectDESCRIPTION ' 我的第一個純 C++ COM 對象 '

EXPORTS DllRegisterServer PRIVATE ; COM server registration DllUnregisterServer PRIVATE ; COM server deregistration DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE

OLEObject Linking & Embedding

InProcess Severs

by MFC

Example: CalculatorMemory

IMemoey

DECLARE_INTERFACE_(IMemory, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IMemory methods

STDMETHOD(MemoryClear)(THIS) PURE;

STDMETHOD(MemoryRecall)(THIS_ double *) PURE;

STDMETHOD(MemoryPlus)(THIS_ double) PURE;

STDMETHOD(MemoryMinus)(THIS_ double) PURE;

};

DECLARE_INTERFACE_(IMemory, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID, void **) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IMemory methods

STDMETHOD(MemoryClear)(THIS) PURE;

STDMETHOD(MemoryRecall)(THIS_ double *) PURE;

STDMETHOD(MemoryPlus)(THIS_ double) PURE;

STDMETHOD(MemoryMinus)(THIS_ double) PURE;

};

Create MFC Project

Create MFC Project

Create MFC Project

Create COM Objects

CalculatorMemory.h

class CCalculatorMemory : public CCmdTarget{.........................................// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCalculatorMemory) public: virtual void OnFinalRelease(); //}}AFX_VIRTUAL

// Implementationprotected:......................................... DECLARE_OLECREATE(CCalculatorMemory)

// Generated OLE dispatch map functions //{{AFX_DISPATCH(CCalculatorMemory) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_DISPATCH DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP()};

class CCalculatorMemory : public CCmdTarget{.........................................// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCalculatorMemory) public: virtual void OnFinalRelease(); //}}AFX_VIRTUAL

// Implementationprotected:......................................... DECLARE_OLECREATE(CCalculatorMemory)

// Generated OLE dispatch map functions //{{AFX_DISPATCH(CCalculatorMemory) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_DISPATCH DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP()};

CalculatorMemory.h

class CCalculatorMemory : public CCmdTarget{.........................................// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCalculatorMemory) public: virtual void OnFinalRelease(); //}}AFX_VIRTUAL

// Implementationprotected:......................................... DECLARE_OLECREATE(CCalculatorMemory)

// Generated OLE dispatch map functions //{{AFX_DISPATCH(CCalculatorMemory) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_DISPATCH DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP()};

class CCalculatorMemory : public CCmdTarget{.........................................// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCalculatorMemory) public: virtual void OnFinalRelease(); //}}AFX_VIRTUAL

// Implementationprotected:......................................... DECLARE_OLECREATE(CCalculatorMemory)

// Generated OLE dispatch map functions //{{AFX_DISPATCH(CCalculatorMemory) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_DISPATCH DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP()};

CalculatorMemory.Cpp

...........................................................................BEGIN_DISPATCH_MAP(CCalculatorMemory, CCmdTarget) //{{AFX_DISPATCH_MAP(CCalculatorMemory) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAPEND_DISPATCH_MAP()

// Note: we add support for IID_ICalculatorMemory to support typesafe binding// from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file.

// {07B9A7FE-DAD0-4865-9E96-43794803D4E7}static const IID IID_ICalculatorMemory ={ 0x7b9a7fe, 0xdad0, 0x4865, { 0x9e, 0x96, 0x43, 0x79, 0x48, 0x3, 0xd4, 0xe7 } };

BEGIN_INTERFACE_MAP(CCalculatorMemory, CCmdTarget) INTERFACE_PART(CCalculatorMemory, IID_ICalculatorMemory, Dispatch)END_INTERFACE_MAP()

// {E928B5CD-8700-48B3-9D74-21E7C76F4B35}IMPLEMENT_OLECREATE(CCalculatorMemory, "CalculatorMemory", ..........)...........................................................................

...........................................................................BEGIN_DISPATCH_MAP(CCalculatorMemory, CCmdTarget) //{{AFX_DISPATCH_MAP(CCalculatorMemory) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAPEND_DISPATCH_MAP()

// Note: we add support for IID_ICalculatorMemory to support typesafe binding// from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file.

// {07B9A7FE-DAD0-4865-9E96-43794803D4E7}static const IID IID_ICalculatorMemory ={ 0x7b9a7fe, 0xdad0, 0x4865, { 0x9e, 0x96, 0x43, 0x79, 0x48, 0x3, 0xd4, 0xe7 } };

BEGIN_INTERFACE_MAP(CCalculatorMemory, CCmdTarget) INTERFACE_PART(CCalculatorMemory, IID_ICalculatorMemory, Dispatch)END_INTERFACE_MAP()

// {E928B5CD-8700-48B3-9D74-21E7C76F4B35}IMPLEMENT_OLECREATE(CCalculatorMemory, "CalculatorMemory", ..........)...........................................................................

CalculatorMemory.Cpp

...........................................................................BEGIN_DISPATCH_MAP(CCalculatorMemory, CCmdTarget) //{{AFX_DISPATCH_MAP(CCalculatorMemory) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAPEND_DISPATCH_MAP()

// Note: we add support for IID_ICalculatorMemory to support typesafe binding// from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file.

// {07B9A7FE-DAD0-4865-9E96-43794803D4E7}static const IID IID_ICalculatorMemory ={ 0x7b9a7fe, 0xdad0, 0x4865, { 0x9e, 0x96, 0x43, 0x79, 0x48, 0x3, 0xd4, 0xe7 } };

BEGIN_INTERFACE_MAP(CCalculatorMemory, CCmdTarget) INTERFACE_PART(CCalculatorMemory, IID_ICalculatorMemory, Dispatch)END_INTERFACE_MAP()

// {E928B5CD-8700-48B3-9D74-21E7C76F4B35}IMPLEMENT_OLECREATE(CCalculatorMemory, "CalculatorMemory", ..........)...........................................................................

...........................................................................BEGIN_DISPATCH_MAP(CCalculatorMemory, CCmdTarget) //{{AFX_DISPATCH_MAP(CCalculatorMemory) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAPEND_DISPATCH_MAP()

// Note: we add support for IID_ICalculatorMemory to support typesafe binding// from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file.

// {07B9A7FE-DAD0-4865-9E96-43794803D4E7}static const IID IID_ICalculatorMemory ={ 0x7b9a7fe, 0xdad0, 0x4865, { 0x9e, 0x96, 0x43, 0x79, 0x48, 0x3, 0xd4, 0xe7 } };

BEGIN_INTERFACE_MAP(CCalculatorMemory, CCmdTarget) INTERFACE_PART(CCalculatorMemory, IID_ICalculatorMemory, Dispatch)END_INTERFACE_MAP()

// {E928B5CD-8700-48B3-9D74-21E7C76F4B35}IMPLEMENT_OLECREATE(CCalculatorMemory, "CalculatorMemory", ..........)...........................................................................

Example: CalculatorMemory

View Source Code

Exercises

10. Implement a simple calculator COM Sever by MFC.

11. Understanding what it is IDispatch.12. Understanding string data type BSTR.13. Understanding VARIANT data structure an

d its usages.