8/10/2019 09 COM Fundamentals1
1/49
FundamentalsFundamentalsOf COM(+)Of COM(+)
(Part 1)(Part 1)
Don BoxDon BoxCofounder Cofounder
DevelopMentor DevelopMentor http://http:// www.develop.com/dboxwww.develop.com/dbox
1111 --203203
8/10/2019 09 COM Fundamentals1
2/49
COMCOM The IdeaThe IdeaCOM is based on three fundamental ideasCOM is based on three fundamental ideas
Clients program in terms of interfaces,Clients program in terms of interfaces,not classesnot classesImplementation code is not statically linked,Implementation code is not statically linked,
but rather loaded onbut rather loaded on --demand at runtimedemand at runtimeObjectObject implementorsimplementors declare their runtimedeclare their runtimerequirements and the system ensures thatrequirements and the system ensures thatthese requirements are metthese requirements are metThe former two are the core of classic COMThe former two are the core of classic COMThe latter is the core of MTS and COM+The latter is the core of MTS and COM+
8/10/2019 09 COM Fundamentals1
3/49
Tale Of TwoTale Of Two COMsCOMsCOM is used primarily for two tasksCOM is used primarily for two tasksTask 1: Gluing together multiple components insideTask 1: Gluing together multiple components insidea processa process
Class loading, type information, etcClass loading, type information, etc
Task 2: Inter Task 2: Inter --process/Inter process/Inter --host communicationshost communications
ObjectObject --based Remote Procedure Calls (ORPC)based Remote Procedure Calls (ORPC)Pros: Same programming model and APIs used forPros: Same programming model and APIs used forboth tasksboth tasksCons: Same programming model and APIs used forCons: Same programming model and APIs used forboth tasksboth tasksDesign around the task at handDesign around the task at hand
8/10/2019 09 COM Fundamentals1
4/49
MotivationMotivationWe want to build dynamicallyWe want to build dynamically composablecomposable systemssystems
Not all parts of application are statically linkedNot all parts of application are statically linked
We want to minimize coupling within the systemWe want to minimize coupling within the systemOne change propagates to entire source code treeOne change propagates to entire source code tree
We want plugWe want plug --andand --playplay replaceablityreplaceablity andand
extensibilityextensibilityNew pieces should be indistinguishable from old,New pieces should be indistinguishable from old,known partsknown parts
We want freedom from file/path dependenciesWe want freedom from file/path dependenciesxcopyxcopy /s *. /s *. dlldll C:C: \ \winntwinnt \ \ system32 not a solutionsystem32 not a solution
We want components with different runtimeWe want components with different runtimerequirements to live peaceably together requirements to live peaceably together
Need to mix heterogeneous objects in a single processNeed to mix heterogeneous objects in a single process
8/10/2019 09 COM Fundamentals1
5/49
A SolutionA Solution ComponentsComponentsCircaCirca --19801980 s style objects style object --orientation based onorientation based onclasses and objectsclasses and objects
Classes used for object implementationClasses used for object implementationClasses also used for consumer/client type hierarchyClasses also used for consumer/client type hierarchy
Using classUsing class --based OO introduces nonbased OO introduces non --trivialtrivialcoupling between client and objectcoupling between client and object
Client assumes complete knowledge of public interfaceClient assumes complete knowledge of public interfaceClient may know even more under certain languagesClient may know even more under certain languages(e.g., C++)(e.g., C++)
CircaCirca --19901990 s object orientation separates clients object orientation separates client --visible type system from objectvisible type system from object --visiblevisibleimplementationimplementation
Allows client to program in terms of abstract typesAllows client to program in terms of abstract types
When done properly, completely hides implementationWhen done properly, completely hides implementationclass from clientclass from client
8/10/2019 09 COM Fundamentals1
6/49
// faststring.h/ faststring.h seen by client and objecteen by client and object implementormplementorclasslass FastStringastString {
char *har * m_psz_psz ;
public:ublic:FastString(const char *astString(const char * pszsz );;~FastString();FastString();int Length() const;nt Length() const;int Find(const char *nt Find(const char * pszSearchStringszSearchString ) const;const;
};;
/// faststring.cppaststring.cpp seen by objecteen by object implementormplementor onlynlyFastString::FastString(constastString::FastString(const char *har * pszsz )
: : : : :
Recall: ClassRecall: Class --BasedBased ooooThe objectThe object implementor implementor defines a class thatdefines a class that
Is used to produce new objectsIs used to produce new objectsIs used by the client to instantiate and invoke methodsIs used by the client to instantiate and invoke methods
8/10/2019 09 COM Fundamentals1
7/49
Recall: ClassRecall: Class --BasedBased ooooClient expected to import full definition of classClient expected to import full definition of class
Includes complete public signature at time of compilationIncludes complete public signature at time of compilationAlso includes size/offset information under C++Also includes size/offset information under C++
/// client.cpplient.cpp// import type definitions to use object/ import type definitions to use object
#includeinclude
faststring.haststring.h
intnt FindTheOffsetindTheOffset ( ) { ) {intnt i == -1;;FastStringastString *pfsfs = newnew FastString(astString( Helloello , WorldWorld ); ;if (f ( pfsfs ) { {
i == pfsfs ->Find(Find( o, W, W ); ;deleteelete pfsfs ;}return i;eturn i;
}
8/10/2019 09 COM Fundamentals1
8/49
ClassClass --Based OO PitfallsBased OO PitfallsClasses notClasses not soso bad when the world is statically linkedbad when the world is statically linked
Changes to class and client happen simultaneouslyChanges to class and client happen simultaneouslyProblematic if existing public interface changesProblematic if existing public interface changes
Most environments do a poor job at distinguishingMost environments do a poor job at distinguishingchanges to public interface from private detailschanges to public interface from private details
Touching private members usually triggers cascading rebuildTouching private members usually triggers cascading rebuild
Static linking has many drawbacksStatic linking has many drawbacksCode size bigger Code size bigger CanCan t replace class code independentlyt replace class code independently
Open Question:Open Question: Can classes be dynamically linked?Can classes be dynamically linked?
8/10/2019 09 COM Fundamentals1
9/49
// faststring.h/ faststring.h
classlass __declspec(dllexport)_declspec(dllexport) FastStringastString {char *har * m_psz_psz ;
public:ublic:
FastString(const char *astString(const char * pszsz );;~FastString();FastString();int Length() const;nt Length() const;int Find(const char *nt Find(const char * pszSearchStringszSearchString ) const;const;
};;
Classes Versus Dynamic LinkingClasses Versus Dynamic Linking
Most compilers offer a compiler keyword orMost compilers offer a compiler keyword ordirective to export all class members from DLLdirective to export all class members from DLL
Results in mechanical change at build/runResults in mechanical change at build/run --timetimeRequires zero change to source code (except introducingRequires zero change to source code (except introducingthe directive)the directive)
8/10/2019 09 COM Fundamentals1
10/49
Classes Versus Dynamic LinkingClasses Versus Dynamic Linking
Client AClient AClients statically link toClients statically link toimport libraryimport library
Maps symbolic name to DLLMaps symbolic name to DLLand entry nameand entry name
Client imports resolved atClient imports resolved atload timeload timeNote: C++ compilers nonNote: C++ compilers non --standardstandard wrtwrt DLLsDLLs
DLL and clients must be builtDLL and clients must be builtusing same compiler/linker using same compiler/linker
Client BClient B
Client CClient C
faststring.dllfaststring.dll
import namemport name file nameile name export namexport name
??@3fFastString_6Length?@3fFastString_6Length??@3fFastString_4Find?@3fFastString_4Find??@3fFastString_ctor@sz2?@3fFastString_ctor@sz2??@3fFastString_dtor?@3fFastString_dtor
faststring.dllaststring.dllfaststring.dllaststring.dllfaststring.dllaststring.dllfaststring.dllaststring.dll
??@3fFastString_6Length?@3fFastString_6Length??@3fFastString_4Find?@3fFastString_4Find??@3fFastString_ctor@sz2?@3fFastString_ctor@sz2??@3fFastString_dtor?@3fFastString_dtor
faststring.lib
8/10/2019 09 COM Fundamentals1
11/49
// faststring.h/ faststring.hclass FastString {lass FastString {
char *har * m_psz_psz ;public:ublic:
FastString(const char *astString(const char * pszsz );;~FastString();FastString();int Length() const;nt Length() const;int Find(const char *nt Find(const char * pszSearchStringszSearchString ) const;const;
};;
// faststring.cpp/ faststring.cpp#includeinclude faststring.haststring.h #include include
int FastString::Length() const {nt FastString::Length() const {returneturn strlen(m_psztrlen(m_psz );;
}
Classes Versus DynamicClasses Versus DynamicLinking: EvolutionLinking: Evolution
Challenge: Improve the performance of Length!Challenge: Improve the performance of Length!Do not change publicDo not change publicinterface and breakinterface and breakencapsulationencapsulation
8/10/2019 09 COM Fundamentals1
12/49
class __declspec(dllexport) FastStringlass __declspec(dllexport) FastString{
char *har * m_psz_psz ;intnt m_cch_cch ;public:ublic:
FastString(const char *astString(const char * pszsz );;~FastString();FastString();
int Length() const;nt Length() const;int Find(const char *nt Find(const char * pszSSszSS ) const;const;
};;
FastString::FastString(const char *sz)astString::FastString(const char *sz): m_psz(new_psz(new char[strlen(sz)+1]),har[strlen(sz)+1]),
m_cch(strlen(sz_cch(strlen(sz )) {) {
strcpy(m_psztrcpy(m_psz , sz); sz);}
int FastString::Length() const {nt FastString::Length() const {returneturn m_cch_cch ;
}
Classes Versus DynamicClasses Versus DynamicLinking: EvolutionLinking: Evolution
Solution: Speed up FastString::Length by cachingSolution: Speed up FastString::Length by cachinglength as data member length as data member
8/10/2019 09 COM Fundamentals1
13/49
Client AClient A
Client BClient B
Client CClient C
faststring.dllfaststring.dll
sizeofsizeof ==8==8
sizeofsizeof ==8==8sizeofsizeof ==4==4
sizeofsizeof ==4==4
Classes Versus DynamicClasses Versus DynamicLinking: EvolutionLinking: Evolution
New DLL assumesNew DLL assumessizeof(FastStringsizeof(FastString ) is 8) is 8Existing Clients assumeExisting Clients assumesizeof(FastStringsizeof(FastString ) is 4) is 4Clients that want newClients that want new
functionality recompilefunctionality recompileOld Clients break!Old Clients break!This is an inherentThis is an inherentlimitation of virtually alllimitation of virtually all
C++ environmentsC++ environments
8/10/2019 09 COM Fundamentals1
14/49
Client AClient A(v2)(v2)
faststring.dllfaststring.dll(v1)(v1)
FastString::FastStringFastString::FastStringFastString::~FastStringFastString::~FastStringFastString::LengthFastString::LengthFastString::FindFastString::Find
FastString::FastStringFastString::FastStringFastString::~FastStringFastString::~FastString
FastString::LengthFastString::LengthFastString::FindFastString::Find
FastString::FindNFastString::FindN
Classes Versus DynamicClasses Versus DynamicLinking: Interface EvolutionLinking: Interface Evolution
Adding new public methods OK when statically linkedAdding new public methods OK when statically linkedClass and client code inseparableClass and client code inseparable
Adding public methods to a DLLAdding public methods to a DLL --based class dangerous!based class dangerous!New client expects method to be thereNew client expects method to be thereOld DLLs have never heard of this method!!Old DLLs have never heard of this method!!
8/10/2019 09 COM Fundamentals1
15/49
ConclusionsConclusions
Cannot change definition of a dataCannot change definition of a data
type without massivetype without massiverebuild/redeployment of client/objectrebuild/redeployment of client/objectIf clients program in terms of classes,If clients program in terms of classes,
then classes cannot change in anythen classes cannot change in anymeaningful waymeaningful wayClasses must change because weClasses must change because wecancan t get it right the first timet get it right the first timeSolution: Clients must not programSolution: Clients must not programin terms of classesin terms of classes
8/10/2019 09 COM Fundamentals1
16/49
InterfaceInterface
--BasedBased
ProgrammingProgrammingKey to solving the replaceable component problem isKey to solving the replaceable component problem isto split the world into twoto split the world into twoThe types the client programs against can neverThe types the client programs against can neverchangechange
Since classes need to change, these better not be classes!Since classes need to change, these better not be classes!Solution based on defining alternative type systemSolution based on defining alternative type systembased on abstract types called interfacesbased on abstract types called interfacesAllowing client to only see interfaces insulates clientsAllowing client to only see interfaces insulates clientsfrom changes to underlying class hierarchyfrom changes to underlying class hierarchyMost common C++ technique for bridging interfacesMost common C++ technique for bridging interfacesand classes is to use abstract baseand classes is to use abstract baseclasses as interfacesclasses as interfaces
8/10/2019 09 COM Fundamentals1
17/49
Abstract Bases AsAbstract Bases AsInterfacesInterfaces
A class can be designated as abstract by makingA class can be designated as abstract by making(at least) one method(at least) one method pure virtualpure virtual
structstruct IFastStringIFastString {{virtualvirtual intint Length( ) const = 0;Length( ) const = 0;virtualvirtual intint Find(const char *) const = 0;Find(const char *) const = 0;
};};
Cannot instantiate abstract baseCannot instantiate abstract baseCan declare pointers or references to abstract basesCan declare pointers or references to abstract bases
Must instead derive concrete type that implementsMust instead derive concrete type that implementseach pure virtual functioneach pure virtual functionClasses withClasses with onlyonly pure virtual functions (no datapure virtual functions (no datamembers, no implementation code) often calledmembers, no implementation code) often called
pure abstract bases, protocol classespure abstract bases, protocol classes oror interfacesinterfaces
8/10/2019 09 COM Fundamentals1
18/49
Interfaces AndInterfaces AndImplementationsImplementations
Given an abstract interface, the most common wayGiven an abstract interface, the most common wayto associate an implementation with it isto associate an implementation with it isthrough inheritancethrough inheritance
ClassClass FastStringFastString : public: public IFastStringIFastString {...};{...};
Implementation type must provide concreteImplementation type must provide concreteimplementations of each interface methodimplementations of each interface methodSome mechanism needed to create instances of theSome mechanism needed to create instances of theimplementation type without exposing layoutimplementation type without exposing layout
Usually takes the form of a creator or factory functionUsually takes the form of a creator or factory functionMust provide client with a way to delete objectMust provide client with a way to delete object
Since the new operator is not used by the client, it cannotSince the new operator is not used by the client, it cannotcall the delete operator call the delete operator
8/10/2019 09 COM Fundamentals1
19/49
Exporting Via Abstract BasesExporting Via Abstract Bases
/// faststringclient.haststringclient.h common header between client/classommon header between client/class
// here/ here s the DLL the DLL -friendly abstract interface:riendly abstract interface:structtruct IFastStringFastString {
virtual voidirtual void Deleteelete () = 0;) = 0;virtual int Length() const = 0;irtual int Length() const = 0;virtual int Find(const char *sz) const = 0;irtual int Find(const char *sz) const = 0;
};;
// and here/ and here s the DLL the DLL -friendly factory function:riendly factory function:externxtern C booloolCreateInstancereateInstance (constconst char *har * pszClassNameszClassName , // which class? // which class?
const char *onst char * pszsz , // // ctortor argsrgsIFastStringFastString *** ppfspfs ); // the; // the objrefbjref
8/10/2019 09 COM Fundamentals1
20/49
Exporting Via Abstract BasesExporting Via Abstract Bases// faststring.h/ faststring.h private source file of classrivate source file of class#includeinclude faststringclient.haststringclient.h class FastString : publiclass FastString : public IFastStringFastString {// normal prototype of/ normal prototype of FastStringastString class + Deletelass + Delete
void Delete() {oid Delete() { deleteelete this; }his; }};;
/// component.cppomponent.cpp private source file for entire DLLrivate source file for entire DLL#includeinclude faststring.haststring.h // import/ import FastStringastString#includeinclude fasterstring.hasterstring.h // import/ import FasterStringasterString (another class)another class)
boolool CreateInstance(constreateInstance(const char *har * pszClassNameszClassName ,const char *onst char * pszsz , IFastStringFastString *** ppfspfs ) { {
*ppfspfs = 0; 0;
if (f ( strcmp(pszClassNametrcmp(pszClassName , FastStringastString ) == 0)== 0)*ppfspfs = static_cast< static_cast< IFastStringFastString *>(>( newew FastString(szastString(sz )););
else if (lse if ( strcmp(pszClassNametrcmp(pszClassName , FasterStringasterString ) == 0)== 0)*ppfspfs = static_cast< static_cast< IFastStringFastString *>(>( newew FasterString(szasterString(sz )););
return *eturn * ppfspfs = 0;= 0;}
8/10/2019 09 COM Fundamentals1
21/49
m_text m_text
m_lengthm_length
vptrvptr FastString::DeleteFastString::Delete
FastString::LengthFastString::Length
FastString::FindFastString::Find
pfspfs
ClientClient ObjectObject
Exporting UsingExporting UsingAbstract BasesAbstract Bases
8/10/2019 09 COM Fundamentals1
22/49
boolool LoadAndCreate(constoadAndCreate(const char *har * szDLLzDLL, const char *sz, const char *sz,IFastStringFastString *** ppfspfs ){{
HINSTANCE h =INSTANCE h = LoadLibrary(szDLLoadLibrary(szDLL );;
boolool (** fp)(constp)(const char*, const char*,har*, const char*, IFastStringFastString **);*);*((FARPROC*)&((FARPROC*)& fpp ) == GetProcAddress(hetProcAddress(h , CreateInstancereateInstance ); ;returneturn fp(p( FastStringastString , sz z , ppfspfs );;
}
Interfaces AndInterfaces AndPlugPlug --compatibilitycompatibility
Note that a particular DLL can supply multiple implementationsNote that a particular DLL can supply multiple implementationsof same interfaceof same interface
CreateInstance(CreateInstance( SlowStringSlowString ,, Hello!!Hello!! , &, &pfspfs ););
Due to simplicity of model, runtime selection of Due to simplicity of model, runtime selection of implementation trivialimplementation trivial
Explicitly load DLL and bind function addressExplicitly load DLL and bind function address
8/10/2019 09 COM Fundamentals1
23/49
Interfaces And EvolutionInterfaces And EvolutionPrevious slides alluded to interface remainingPrevious slides alluded to interface remainingconstant across versionsconstant across versions
InterfaceInterface --based development mandates that newbased development mandates that newfunctionality be exposed using additional interfacefunctionality be exposed using additional interface
Extended functionality provided by deriving fromExtended functionality provided by deriving fromexisting interfaceexisting interface
Orthogonal functionality provided by creating newOrthogonal functionality provided by creating newsibling interfacesibling interface
Some technique needed for dynamicallySome technique needed for dynamicallyinterrogating an object for interface supportinterrogating an object for interface support
Most languages support some sort of runtime castMost languages support some sort of runtime castoperation (e.g., C++operation (e.g., C++ s dynamic_cast)s dynamic_cast)
8/10/2019 09 COM Fundamentals1
24/49
/// faststringclient.haststringclient.hstructtruct IFastNFindFastNFind : public IFastString { public IFastString {
virtual int FindN(const char *irtual int FindN(const char * szz , int n) const = 0; int n) const = 0;
};; /// faststringclient.cxxaststringclient.cxx
int Find10thInstanceOfFoo(IFastString *nt Find10thInstanceOfFoo(IFastString * pfsfs ) { {IFastNFindFastNFind *pfnffnf = 0; 0;
if (f ( pfnffnf = dynamic_cast>(pfsfs )) {) {returneturn pfnffnf ->FindN(indN( Foooo , 10); 10);}elselse
// implement by hand.../ implement by hand...
}
Example: AddingExample: AddingExtended FunctionalityExtended Functionality
Add method to find the nth instance of szAdd method to find the nth instance of sz
8/10/2019 09 COM Fundamentals1
25/49
m_textm_text
m_lengthm_length
vptr vptr
FastString::DeleteFastString::Delete
FastString::LengthFastString::Length
FastString::FindFastString::Find
pfspfs
ClientClient ObjectObject
pfnf pfnf FastString::FindNFastString::FindN
Example: AddingExample: AddingExtended FunctionalityExtended Functionality
8/10/2019 09 COM Fundamentals1
26/49
/// faststringclient.haststringclient.hstructtruct IPersistentObjectPersistentObject {
virtual void Delete(void) = 0;irtual void Delete(void) = 0;virtualirtual boolool Load(const char *oad(const char * szz ) = 0; = 0;virtualirtual boolool Save(const char *ave(const char * szz ) const = 0; const = 0;
};;
/// faststringclient.cxxaststringclient.cxx
boolool SaveString(IFastStringaveString(IFastString *pfsfs ) { {
IPersistentObjectPersistentObject *ppopo = 0; 0;if (f ( ppopo = dynamic_cast>(pfsfs )) {) {
returneturn ppopo ->Save(Save( Autoexec.batutoexec.bat ); ;}elselse
return false; // cannot save...eturn false; // cannot save...
}
Example: AddingExample: AddingOrthogonal FunctionalityOrthogonal Functionality
Add support for generic persistenceAdd support for generic persistence
8/10/2019 09 COM Fundamentals1
27/49
m_textm_text
m_lengthm_length
vptrvptrFastString::DeleteFastString::DeleteFastString::LengthFastString::Length
FastString::FindFastString::Find
pfspfs
Client Object
vptrvptr
FastString::DeleteFastString::DeleteFastString::LoadFastString::Load
ppoppo
FastString::SaveFastString::Save
Example: AddingExample: AddingOrthogonal FunctionalityOrthogonal Functionality
8/10/2019 09 COM Fundamentals1
28/49
Fixing InterfaceFixing Interface --BasedBasedProgramming In C++Programming In C++
The dynamic_cast operator has several problemsThe dynamic_cast operator has several problemsthat must be addressedthat must be addressed
1) Its implementation is non1) Its implementation is non --standard across compilersstandard across compilers2) There is no standard runtime representation2) There is no standard runtime representationfor thefor the typenametypename3) Two parties may choose colliding3) Two parties may choose colliding typenamestypenames
Can solve #1 by adding yet another wellCan solve #1 by adding yet another well --knownknownabstract method to each interface (a la Delete)abstract method to each interface (a la Delete)
#2 and #3 solved by using a well#2 and #3 solved by using a well --knownknownnamespace/type format for identifying interfacesnamespace/type format for identifying interfacesUUIDsUUIDs from OSF DCE are compact (128 bit), efficient andfrom OSF DCE are compact (128 bit), efficient andguarantee uniquenessguarantee uniqueness
UUIDsUUIDs are basically big, unique integers!are basically big, unique integers!
8/10/2019 09 COM Fundamentals1
29/49
QueryInterfaceQueryInterfaceCOM programmers use the wellCOM programmers use the well --known abstractknown abstractmethod (method ( QueryInterfaceQueryInterface ) in lieu of dynamic_cast) in lieu of dynamic_cast
virtual HRESULT _ virtual HRESULT _ stdcallstdcallQueryInterface(REFIIDQueryInterface(REFIID riidriid ,// the requested UUID,// the requested UUIDvoid **void ** ppvppv // the resultant // the resultant objref objref ) = 0;) = 0;
Returns status code indicating success (S_OK) orReturns status code indicating success (S_OK) orfailure (E_NOINTERFACE)failure (E_NOINTERFACE)UUID is integral part of interface definitionUUID is integral part of interface definition
Defined as a variable with IID_ prefixed to type nameDefined as a variable with IID_ prefixed to type nameVCVC--specific __ specific __ declspec(uuiddeclspec(uuid ) conjoins COM/C++ names) conjoins COM/C++ names
8/10/2019 09 COM Fundamentals1
30/49
voidoid UseAsTelephone(ICalculatorseAsTelephone(ICalculator *pCalcCalc ) { {ITelephoneTelephone *pPhonePhone = 0; 0;pPhonePhone = dynamic_cast< dynamic_cast< ITelephoneTelephone *>(>( pCalcCalc );;if (f ( pPhonePhone ) { {
// use/ use pPhonePhone
: : : : :
voidoid UseAsTelephone(ICalculatorseAsTelephone(ICalculator *pCalcCalc ) { {ITelephoneTelephone *pPhonePhone = 0; 0;
HRESULT hr =RESULT hr = pCalcCalc ->QueryInterface(IID_ITelephoneueryInterface(IID_ITelephone ,(void**)&void**)& pPhonePhone );;
if (hr == S_OK) {f (hr == S_OK) {// use/ use pPhonePhone
: : : : :
QueryInterfaceQueryInterface As A BetterAs A BetterDynamic CastDynamic Cast
8/10/2019 09 COM Fundamentals1
31/49
ICalculatorCalculator *pCalc1 =pCalc1 = CreateCalcreateCalc (););ITelephoneTelephone *pPhone1 =pPhone1 = CreatePhonereatePhone (););ICalculatorCalculator *pCalc2 = dynamic_cast(pPhone1);>(pPhone1);ICalculatorCalculator *pCalc3 =pCalc3 = CreateCalcreateCalc (););
pPhone1Phone1 ->Dial(pCalc1Dial(pCalc1 ->Add(pCalc2Add(pCalc2 ->Add(pCalc3Add(pCalc3 ->Add(2))));Add(2))));
pCalc1Calc1 ->Delete(); // assume interfaces have DeleteDelete(); // assume interfaces have DeletepCalc2Calc2 ->Delete(); // per earlier discussionDelete(); // per earlier discussionpPhone1Phone1 ->Delete();Delete();
Fixing InterfaceFixing Interface --BasedBasedProgramming In C++Programming In C++
Previous examples used aPrevious examples used a DeleteDelete method to allowmethod to allowclient to destroy objectclient to destroy object
Requires client to remember which references point toRequires client to remember which references point towhich objects to ensure each object deleted exactly oncewhich objects to ensure each object deleted exactly once
8/10/2019 09 COM Fundamentals1
32/49
Fixing InterfaceFixing Interface --BasedBasedProgramming In C++Programming In C++
COM solves theCOM solves the DeleteDelete problem withproblem withreference countingreference counting
Clients blindlyClients blindly DeleteDelete each reference, not each objecteach reference, not each object
Objects can track number of extant references andObjects can track number of extant references and
autoauto --delete when count reaches zerodelete when count reaches zeroRequires 100% compliance with ref. counting rulesRequires 100% compliance with ref. counting rulesAll operations that return interface pointers mustAll operations that return interface pointers mustincrement the interface pointer increment the interface pointer s reference counts reference count
QueryInterfaceQueryInterface ,, CreateInstanceCreateInstance , etc., etc.Clients must inform object that a particular interfaceClients must inform object that a particular interfacepointer has been destroyed using wellpointer has been destroyed using well --known methodknown method
Virtual ULONG _ Virtual ULONG _ stdcallstdcall Release( ) = 0;Release( ) = 0;
8/10/2019 09 COM Fundamentals1
33/49
ICalculatorCalculator *pCalc1 =pCalc1 = CreateCalcreateCalc (););ITelephoneTelephone *pPhone1 =pPhone1 = CreatePhonereatePhone (););
ICalculatorCalculator *pCalc2 = 0;pCalc2 = 0;ICalculatorCalculator *pCalc3 =pCalc3 = CreateCalcreateCalc (););ITelephoneTelephone *pPhone2 = 0;pPhone2 = 0;ICalculatorCalculator *pCalc4 = 0;pCalc4 = 0;
pPhone1Phone1 ->QueryInterface(IID_ICalculator,(voidueryInterface(IID_ICalculator,(void **)&pCalc2);*)&pCalc2);pCalc3Calc3 ->QueryInterface(IID_ITelephone,(voidueryInterface(IID_ITelephone,(void **)&pPhone2);*)&pPhone2);pCalc1Calc1 ->QueryInterface(IID_ICalculatorueryInterface(IID_ICalculator , (void**)&pCalc4); (void**)&pCalc4);
pPhone1Phone1 ->Dial(pCalc1Dial(pCalc1 ->Add(pCalc2Add(pCalc2 ->Add(pCalc3Add(pCalc3 ->Add(2))));Add(2))));
pCalc1Calc1 ->Release(); pCalc4Release(); pCalc4 ->Release();Release();pCalc2Calc2 ->Release(); pPhone1Release(); pPhone1 ->Release();Release();
pCalc3Calc3 ->Release(); pPhone2Release(); pPhone2 ->Release();Release();
Reference Counting BasicsReference Counting Basics
8/10/2019 09 COM Fundamentals1
34/49
extern const IIDxtern const IID IID_IUnknownID_IUnknown ;structtruct IUnknownUnknown {
virtual HRESULT STDMETHODCALLTYPEirtual HRESULT STDMETHODCALLTYPE QueryInterfaceueryInterface (const IID&onst IID& riidiid , void ** void ** ppvpv ) = 0; = 0;
virtual ULONG STDMETHODCALLTYPEirtual ULONG STDMETHODCALLTYPE AddRefddRef ( ) = 0; ) = 0;virtual ULONG STDMETHODCALLTYPE Release( ) = 0;irtual ULONG STDMETHODCALLTYPE Release( ) = 0;
};;
IUnknownIUnknownThe three core abstract operations (The three core abstract operations ( QueryInterfaceQueryInterface ,,AddRef AddRef , and Release) comprise the core interface, and Release) comprise the core interface
of COM,of COM, IUnknownIUnknownAll COM interfaces must extendAll COM interfaces must extend IUnknownIUnknownAll COM objects must implementAll COM objects must implement IUnknownIUnknown
8/10/2019 09 COM Fundamentals1
35/49
8/10/2019 09 COM Fundamentals1
36/49
Com Interfaces In NatureCom Interfaces In Nature
COM interfaces are described first inCOM interfaces are described first inCOM IDLCOM IDLCOM IDL is an extension to DCE IDLCOM IDL is an extension to DCE IDL
Support for objects + various wire optimizationsSupport for objects + various wire optimizations
IDL compiler directly emits C/C++ interfaceIDL compiler directly emits C/C++ interfacedefinitions as source codedefinitions as source codeIDL compiler emits tokenized type libraryIDL compiler emits tokenized type librarycontaining (most) of original contents in ancontaining (most) of original contents in aneasily parsed formateasily parsed formatJavaJava /Visual Basic /Visual Basic pick up mappings frompick up mappings fromtype librarytype library
8/10/2019 09 COM Fundamentals1
37/49
Foo.idlFoo.idl IDL IDL
DescriptionDescriptionofof FooFoo interfacesinterfacesand datatypesand datatypes
Foo.hFoo.hC/C++C/C++
DefinitionsDefinitions
Foo_i.cFoo_i.cGUIDsGUIDs
Foo_p.cFoo_p.cProxy/StubProxy/Stub
dlldata.cdlldata.cClass LoadingClass Loading
Support Support
Foo.tlbFoo.tlbBinaryBinaryDescriptionsDescriptions
MIDL.EXEMIDL.EXE *.java*.java Java JavaDefinitionsDefinitions
JACTIVEX.EXEJACTIVEX.EXE
COM IDLCOM IDL
8/10/2019 09 COM Fundamentals1
38/49
COM IDLCOM IDLAll elements in an IDL file can have attributesAll elements in an IDL file can have attributes
Appear in [ ] prior to subject of attributesAppear in [ ] prior to subject of attributes
Interfaces are defined at global scopeInterfaces are defined at global scopeRequired by MIDL to emit networking codeRequired by MIDL to emit networking code
Must refer to exported types inside library blockMust refer to exported types inside library block
Required by MIDL to emit type library definitionRequired by MIDL to emit type library definitionCan import std interface suiteCan import std interface suite
WTYPES.IDLWTYPES.IDL -- basic data typesbasic data typesUNKNWN.IDLUNKNWN.IDL -- core type interfacescore type interfaces
OBJIDL.IDLOBJIDL.IDL -- core infrastructurecore infrastructure itfsitfsOLEIDL.IDLOLEIDL.IDL -- OLEOLE itfsitfsOAIDL.IDLOAIDL.IDL -- AutomationAutomation itfsitfsOCIDL.IDLOCIDL.IDL -- ActiveX ControlActiveX Control itfsitfs
8/10/2019 09 COM Fundamentals1
39/49
[ uuid(DEFACED1 uuid(DEFACED1 -0229229 -2552552 -1D11D11 -ABBADABBAD00), object ]BBADABBAD00), object ]interfacenterface ICalculatorCalculator : IDesktopDeviceDesktopDevice {
importmport dd.idld.idl ; // bring in// bring in IDesktopDeviceDesktopDeviceHRESULT Clear(void);RESULT Clear(void);HRESULT Add([in] short n); // n sent to objectRESULT Add([in] short n); // n sent to objectHRESULTRESULT GetSum([outetSum([out ] short * short * pnn ); // *; // * pnn sent to callerent to caller
}
[uuid(DEFACED2uid(DEFACED2 -0229229 -2552552 -1D11D11 -ABBADABBAD00),BBADABBAD00),helpstring(elpstring( Myy Datatypesatatypes )
]libraryibrary CalcTypesalcTypes {
importlib(mportlib( stdole32.tlbtdole32.tlb ); // required; // requiredinterfacenterface ICalculatorCalculator ; // cause TLB inclusion // cause TLB inclusion
}
CalcTypes.idlCalcTypes.idl
COM IDLCOM IDL
8/10/2019 09 COM Fundamentals1
40/49
COM IDLCOM IDL -- C++ MappingC++ Mapping#includeinclude dd.hd.h extern const IIDxtern const IID IID_ICalculatorID_ICalculator ;structtruct__declspec uuid_declspec uuid DEFACED1EFACED1-0229229 -2552552 -1D11D11 -ABBADABBAD00BBADABBAD00)))ICalculatorCalculator : publicpublic IDesktopDeviceDesktopDevice {
virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;irtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;virtual HRESULT STDMETHODCALLTYPE Add(short n) = 0;irtual HRESULT STDMETHODCALLTYPE Add(short n) = 0;
virtual HRESULT STDMETHODCALLTYPEirtual HRESULT STDMETHODCALLTYPE GetSum(shortetSum(short *pnn ) = 0; = 0;};;extern const GUIDxtern const GUID LIBID_CalcTypesIBID_CalcTypes ;
const IIDonst IID IID_ICalculatorID_ICalculator = {0xDEFACED1, 0x0229, 0x2552, {0xDEFACED1, 0x0229, 0x2552,{ 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } }; 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } };
const GUIDonst GUID LIBID_CalcTypesIBID_CalcTypes = {0xDEFACED2, 0x0229, 0x2552, {0xDEFACED2, 0x0229, 0x2552,{ 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } }; 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } };
CalcTypes.hCalcTypes.h
CalcTypes_i.cCalcTypes_i.c
8/10/2019 09 COM Fundamentals1
41/49
COM IDLCOM IDL Java/VB MappingJava/VB Mapping
packageackage CalcTypesalcTypes ; // library name // library name/**@**@com.interface iidom.interface iid =DEFACED1DEFACED1-0229229 -2552552 -1D11D11 -ABBADABBAD00)*/BBADABBAD00)*/
interfacenterface ICalculatorCalculator extendsxtends IDesktopDeviceDesktopDevice {public void Clear( );ublic void Clear( );public void Add(short n);ublic void Add(short n);public voidublic void GetSum(shortetSum(short []] pnn ); // array of length 1; // array of length 1public staticublic static com.ms.com._Guidom.ms.com._Guid iidid =
new com.ms.com._Guid(0xDEFACED1, 0x0229, 0x2552,ew com.ms.com._Guid(0xDEFACED1, 0x0229, 0x2552,0x1D, 0x11, 0xAB, 0xBA,x1D, 0x11, 0xAB, 0xBA,0xDA, 0xBB, 0xAD, 0x00);xDA, 0xBB, 0xAD, 0x00);
}
CalcTypes.javaCalcTypes.java
Public Sub Clear( )ublic Sub Clear( )Public Subublic Sub Add(ByValdd(ByVal n As Integer) As Integer)Public Subublic Sub GetSum(ByRefetSum(ByRef pnn As Integer)s Integer)
CalcTypes.clsCalcTypes.cls
8/10/2019 09 COM Fundamentals1
42/49
particular valueparticular valueresres
Severity (31)Severity (31) Facility (27Facility (27 --16)16) Code (15Code (15 --0)0)
00 -- > Success> Success11 -- > Failure> Failure
FACILITY_NULLFACILITY_NULLFACILITY_ITFFACILITY_ITFFACILITY_STORAGEFACILITY_STORAGEFACILITY_DISPATCHFACILITY_DISPATCHFACILITY_WINDOWSFACILITY_WINDOWSFACILITY_RPCFACILITY_RPC
COM And Error HandlingCOM And Error HandlingCOM (today) doesnCOM (today) doesn t support typed C++ or Javat support typed C++ or Java --style exceptionsstyle exceptions
All (remotable) methods must return a standard 32All (remotable) methods must return a standard 32 --bit error code called an HRESULTbit error code called an HRESULT
Mapped to exception in higher Mapped to exception in higher --level languageslevel languagesOverloaded to indicate invocation errors from proxiesOverloaded to indicate invocation errors from proxies
8/10/2019 09 COM Fundamentals1
43/49
HRESULTsHRESULTsHRESULT names indicate severity and facilityHRESULT names indicate severity and facility
____DISP_E_EXCEPTIONDISP_E_EXCEPTIONSTG_S_CONVERTEDSTG_S_CONVERTED
FACILITY_NULL codes are implicitFACILITY_NULL codes are implicit__S_OKS_OKS_FALSES_FALSEE_FAILE_FAILE_NOTIMPLE_NOTIMPLE_OUTOFMEMORYE_OUTOFMEMORYE_INVALIDARGE_INVALIDARGE_UNEXPECTEDE_UNEXPECTED
Can useCan use FormatMessageFormatMessage API to lookup humanAPI to lookup human --readablereadabledescription at runtimedescription at runtime
8/10/2019 09 COM Fundamentals1
44/49
smallsmall
longlong
hyperhyper
IDLIDL C++C++ JavaJava
shortshort
charchar
longlong
__int64 __int64
bytebyte
intint
longlong
shortshort shortshort
Visual BasicVisual Basic
N/AN/A
LongLong
N/AN/A
IntegerInteger
unsigned smallunsigned small
unsigned longunsigned long
unsigned hyperunsigned hyper
unsigned shortunsigned short
unsigned charunsigned char
unsigned longunsigned long
unsigned __int64unsigned __int64
bytebyte
intint
longlong
unsigned shortunsigned short shortshort
ByteByte
N/AN/A
N/AN/A
N/AN/A
floatfloat
doubledouble
floatfloat
doubledouble
floatfloat
doubledouble
SingleSingle
DoubleDouble
charchar
unsigned charunsigned char
charchar
unsigned charunsigned char
charchar
bytebyte
N/AN/A
ByteByte
wchar_twchar_t wchar_twchar_t charchar Integer Integer
ScriptScript
NoNo
YesYes
NoNo
YesYes
NoNo
NoNo
NoNo
NoNo
YesYes
YesYes
NoNo
YesYes
NoNo
COM Data TypesCOM Data Types
8/10/2019 09 COM Fundamentals1
45/49
bytebyte
booleanboolean
VARIANT_BOOLVARIANT_BOOL
IDLIDL C++C++ JavaJava
BYTEBYTE
unsigned charunsigned char
longlong
VARIANT_BOOLVARIANT_BOOL
char char
intint
booleanboolean
unsigned charunsigned char bytebyte
Visual BasicVisual Basic
N/AN/A
LongLong
BooleanBoolean
ByteByte
BSTR BSTR
VARIANTVARIANT
BSTR BSTR java.lang.String java.lang.String
VARIANTVARIANT com.ms.com.Variantcom.ms.com.Variant
StringString
VariantVariant
CYCY longlong intint CurrencyCurrency
DATEDATE
enumenum
doubledouble doubledouble
enumenum intint
DateDate
EnumEnum
TypedTyped ObjRef ObjRef IFooIFoo ** interfaceinterface IFooIFoo IFooIFoo
structstruct structstruct final classfinal class TypeType
unionunion
CC-- style Arraystyle Array
unionunion N/AN/A
arrayarray arrayarray
N/AN/A
N/AN/A
ScriptScript
NoNo
NoNo
YesYes
YesYes
YesYes
YesYes
YesYes
YesYes
YesYes
YesYes
NoNo
NoNo
NoNo
COM Data TypesCOM Data Types
8/10/2019 09 COM Fundamentals1
46/49
struct MESSAGE { VARIANT_BOOL b; long n; };truct MESSAGE { VARIANT_BOOL b; long n; };[ uuid(03C20B33 uuid(03C20B33 -C942942 -11d11d1 -926D26D -006008026FEA), object ]06008026FEA), object ]interfacenterface IAnsweringMachineAnsweringMachine : IUnknown { IUnknown {
HRESULTRESULT TakeAMessage([inakeAMessage([in ] struct MESSAGE * struct MESSAGE * pmsgmsg );;[propput] HRESULTpropput] HRESULT OutboundMessage([inutboundMessage([in ] longlong msgsg );;[propget] HRESULTpropget] HRESULT OutboundMessage([oututboundMessage([out , retvaletval ] long *p); long *p);
}
public final class MESSAGE {ublic final class MESSAGE {public boolean b; public int n;ublic boolean b; public int n;
}public interfaceublic interface IAnsweringMachineAnsweringMachine extends IUnknownxtends IUnknown{
public voidublic void TakeAMessage(MESSAGEakeAMessage(MESSAGE msgsg );;public voidublic void putOutboundMessage(intutOutboundMessage(int );;publicublic intnt getOutboundMessageetOutboundMessage (););
}
ExampleExample
8/10/2019 09 COM Fundamentals1
47/49
f
8/10/2019 09 COM Fundamentals1
48/49
ReferencesReferences
Programming Dist Apps With Visual BasicProgramming Dist Apps With Visual Basicand COMand COM
Ted Pattison, Microsoft PressTed Pattison, Microsoft PressInside COMInside COM
DaleDale RogersonRogerson , Microsoft Press, Microsoft Press
Essential COM(+), 2nd Edition (the book)Essential COM(+), 2nd Edition (the book)Don Box, Addison Wesley Longman (4Q99)Don Box, Addison Wesley Longman (4Q99)
Essential COM(+) Short Course,Essential COM(+) Short Course,
DevelopMentor DevelopMentor http://www.develop.comhttp://www.develop.com
DCOM Mailing ListDCOM Mailing List
http://http:// discuss.microsoft.comdiscuss.microsoft.com
8/10/2019 09 COM Fundamentals1
49/49
Top Related