Top Banner
Fundamentals Fundamentals Of COM(+) Of COM(+) (Part 1) (Part 1) Don Box Don Box Cofounder Cofounder DevelopMentor DevelopMentor http://www.develop.com/dbox http://www.develop.com/dbox 11-203 11-203
49

Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor 11-203.

Dec 19, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Fundamentals Fundamentals Of COM(+) Of COM(+) (Part 1)(Part 1)

Don BoxDon BoxCofounderCofounderDevelopMentorDevelopMentorhttp://www.develop.com/dboxhttp://www.develop.com/dbox

11-20311-203

Page 2: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

COM – The IdeaCOM – The Idea

COM 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 classes Implementation code is not statically linked, Implementation code is not statically linked,

but rather loaded on-demand at runtimebut rather loaded on-demand at runtime Object implementors declare their runtime Object implementors declare their runtime

requirements and the system ensures that requirements and the system ensures that these requirements are metthese requirements are met

The former two are the core of classic COMThe former two are the core of classic COM The latter is the core of MTS and COM+The latter is the core of MTS and COM+

Page 3: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Tale Of Two COMsTale Of Two COMs

COM is used primarily for two tasksCOM is used primarily for two tasks Task 1: Gluing together multiple components inside Task 1: Gluing together multiple components inside

a processa process Class loading, type information, etcClass loading, type information, etc

Task 2: Inter-process/Inter-host communicationsTask 2: Inter-process/Inter-host communications Object-based Remote Procedure Calls (ORPC)Object-based Remote Procedure Calls (ORPC)

Pros: Same programming model and APIs used for Pros: Same programming model and APIs used for both tasksboth tasks

Cons: Same programming model and APIs used for Cons: Same programming model and APIs used for both tasksboth tasks

Design around the task at handDesign around the task at hand

Page 4: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

MotivationMotivation

We want to build dynamically composable systemsWe want to build dynamically composable systems 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 system One change propagates to entire source code treeOne change propagates to entire source code tree

We want plug-and-play replaceablity and We want plug-and-play replaceablity and extensibilityextensibility New 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 dependencies xcopy /s *.dll C:\winnt\system32 not a solutionxcopy /s *.dll C:\winnt\system32 not a solution

We want components with different runtime We want components with different runtime requirements to live peaceably togetherrequirements to live peaceably together Need to mix heterogeneous objects in a single processNeed to mix heterogeneous objects in a single process

Page 5: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

A Solution – ComponentsA Solution – Components

Circa-1980’s style object-orientation based on Circa-1980’s style object-orientation based on classes and objectsclasses and objects Classes used for object implementationClasses used for object implementation Classes also used for consumer/client type hierarchyClasses also used for consumer/client type hierarchy

Using class-based OO introduces non-trivial Using class-based OO introduces non-trivial coupling between client and objectcoupling between client and object Client assumes complete knowledge of public interfaceClient assumes complete knowledge of public interface Client may know even more under certain languagesClient may know even more under certain languages

(e.g., C++)(e.g., C++)

Circa-1990’s object orientation separates client-Circa-1990’s object orientation separates client-visible type system from object-visible visible type system from object-visible implementationimplementation Allows client to program in terms of abstract typesAllows client to program in terms of abstract types When done properly, completely hides implementation When done properly, completely hides implementation

class from clientclass from client

Page 6: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

// faststring.h – seen by client and object implementor// faststring.h – seen by client and object implementorclass FastString {class FastString { char *m_psz;char *m_psz;public:public: FastString(const char *psz);FastString(const char *psz); ~FastString();~FastString(); int Length() const;int Length() const; int Find(const char *pszSearchString) const; int Find(const char *pszSearchString) const; };};

// faststring.cpp – seen by object implementor only// faststring.cpp – seen by object implementor onlyFastString::FastString(const char *psz)FastString::FastString(const char *psz) : : :: : :

Recall: Class-Based ooRecall: Class-Based oo

The object implementor defines a class that…The object implementor defines a class that… Is used to produce new objectsIs used to produce new objects Is used by the client to instantiate and invoke methodsIs used by the client to instantiate and invoke methods

Page 7: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Recall: Class-Based ooRecall: Class-Based oo

Client 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 compilation Also includes size/offset information under C++Also includes size/offset information under C++

// client.cpp // client.cpp // import type definitions to use object// import type definitions to use object#include “faststring.h”#include “faststring.h”int FindTheOffset( ) {int FindTheOffset( ) { int i = -1;int i = -1; FastString *pfs = new FastString(“Hello, World!”);FastString *pfs = new FastString(“Hello, World!”); if (pfs) {if (pfs) { i = pfs->Find(“o, W”);i = pfs->Find(“o, W”); delete pfs;delete pfs; }} return i;return i;}}

Page 8: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Class-Based OO PitfallsClass-Based OO Pitfalls Classes not Classes not soso bad when the world is statically linkedbad when the world is statically linked

Changes to class and client happen simultaneously Changes to class and client happen simultaneously Problematic if existing public interface changes…Problematic if existing public interface changes…

Most environments do a poor job at distinguishing changes to public interface from private detailsMost environments do a poor job at distinguishing changes 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 drawbacks Code size biggerCode size bigger Can’t replace class code independently Can’t replace class code independently

Open Question:Open Question: Can classes be dynamically linked?Can classes be dynamically linked?

Page 9: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

// faststring.h// faststring.h

class class __declspec(dllexport)__declspec(dllexport) FastString { FastString { char *m_psz;char *m_psz;public:public: FastString(const char *psz);FastString(const char *psz); ~FastString();~FastString(); int Length() const;int Length() const; int Find(const char *pszSearchString) const; int Find(const char *pszSearchString) const; };};

Classes Versus Dynamic LinkingClasses Versus Dynamic Linking

Most compilers offer a compiler keyword or Most compilers offer a compiler keyword or directive to export all class members from DLLdirective to export all class members from DLL Results in mechanical change at build/run-timeResults in mechanical change at build/run-time Requires zero change to source code (except introducing Requires zero change to source code (except introducing

the directive)the directive)

Page 10: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Classes Versus Dynamic LinkingClasses Versus Dynamic Linking

Client AClient A Clients statically link to import libraryClients statically link to import library

Maps symbolic name to DLL and entry nameMaps symbolic name to DLL and entry name Client imports resolved at load timeClient imports resolved at load time Note: C++ compilers non-standard wrt DLLsNote: C++ compilers non-standard wrt DLLs

DLL and clients must be built using same DLL and clients must be built using same compiler/linkercompiler/linker

Client BClient B

Client CClient C

faststring.dllfaststring.dll

import nameimport name file namefile name export nameexport name

??@3fFastString_6Length??@3fFastString_6Length??@3fFastString_4Find??@3fFastString_4Find??@3fFastString_ctor@sz2??@3fFastString_ctor@sz2??@3fFastString_dtor??@3fFastString_dtor

faststring.dllfaststring.dllfaststring.dllfaststring.dllfaststring.dllfaststring.dllfaststring.dllfaststring.dll

??@3fFastString_6Length??@3fFastString_6Length??@3fFastString_4Find??@3fFastString_4Find??@3fFastString_ctor@sz2??@3fFastString_ctor@sz2??@3fFastString_dtor??@3fFastString_dtor

faststring.lib

Page 11: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

// faststring.h// faststring.hclass FastString {class FastString { char *m_psz;char *m_psz;public:public: FastString(const char *psz);FastString(const char *psz); ~FastString();~FastString(); int Length() const;int Length() const; int Find(const char *pszSearchString) const; int Find(const char *pszSearchString) const; };};

// faststring.cpp// faststring.cpp#include “faststring.h”#include “faststring.h”#include <string.h>#include <string.h>

int FastString::Length() const {int FastString::Length() const { return strlen(m_psz);return strlen(m_psz);}}

Classes Versus Dynamic Classes Versus Dynamic Linking: 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

Page 12: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

class __declspec(dllexport) FastStringclass __declspec(dllexport) FastString{{ char *m_psz;char *m_psz; int m_cchint m_cch;;public:public: FastString(const char *psz);FastString(const char *psz); ~FastString();~FastString(); int Length() const;int Length() const; int Find(const char *pszSS) const; int Find(const char *pszSS) const; };};

FastString::FastString(const char *sz)FastString::FastString(const char *sz): m_psz(new char[strlen(sz)+1]),: m_psz(new char[strlen(sz)+1]), m_cch(strlen(sz)) {m_cch(strlen(sz)) { strcpy(m_psz, sz);strcpy(m_psz, sz);}} int FastString::Length() const {int FastString::Length() const { return m_cch;return m_cch;}}

Classes Versus Dynamic Classes Versus Dynamic Linking: EvolutionLinking: Evolution Solution: Speed up FastString::Length by caching Solution: Speed up FastString::Length by caching

length as data memberlength as data member

Page 13: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Client AClient A

Client BClient B

Client CClient C

faststring.dllfaststring.dll

sizeof==8sizeof==8

sizeof==8sizeof==8sizeof==4sizeof==4

sizeof==4sizeof==4

Classes Versus Dynamic Classes Versus Dynamic Linking: EvolutionLinking: Evolution New DLL assumes New DLL assumes

sizeof(FastString) is 8sizeof(FastString) is 8 Existing Clients assume Existing Clients assume

sizeof(FastString) is 4sizeof(FastString) is 4 Clients that want new Clients that want new

functionality recompile functionality recompile Old Clients break!Old Clients break! This is an inherent This is an inherent

limitation of virtually all C+limitation of virtually all C++ environments+ environments

Page 14: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

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::FindFastString::FindNFastString::FindN

Classes Versus Dynamic Classes Versus Dynamic Linking: Interface EvolutionLinking: Interface Evolution Adding new public methods OK when statically linkedAdding new public methods OK when statically linked

Class and client code inseparableClass and client code inseparable Adding public methods to a DLL-based class dangerous!Adding public methods to a DLL-based class dangerous!

New client expects method to be thereNew client expects method to be there Old DLLs have never heard of this method!!Old DLLs have never heard of this method!!

Page 15: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

ConclusionsConclusions

Cannot change definition of a data Cannot change definition of a data type without massive type without massive rebuild/redeployment of client/objectrebuild/redeployment of client/object

If clients program in terms of classes, If clients program in terms of classes, then classes cannot change in any then classes cannot change in any meaningful waymeaningful way

Classes must change because we Classes must change because we can’t get it right the first timecan’t get it right the first time

Solution: Clients must not programSolution: Clients must not programin terms of classesin terms of classes

Page 16: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Interface-Based Interface-Based ProgrammingProgramming Key to solving the replaceable component problem is Key to solving the replaceable component problem is

to split the world into twoto split the world into two The types the client programs against can never The types the client programs against can never

changechange 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 system Solution based on defining alternative type system based on abstract types called interfacesbased on abstract types called interfaces

Allowing client to only see interfaces insulates clients Allowing client to only see interfaces insulates clients from changes to underlying class hierarchyfrom changes to underlying class hierarchy

Most common C++ technique for bridging interfaces Most common C++ technique for bridging interfaces and classes is to use abstract baseand classes is to use abstract baseclasses as interfacesclasses as interfaces

Page 17: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Abstract Bases As Abstract Bases As InterfacesInterfaces A class can be designated as abstract by making A class can be designated as abstract by making

(at least) one method(at least) one method pure virtual pure virtualstruct IFastString {struct IFastString { virtual int Length( ) const = 0;virtual int Length( ) const = 0; virtual int Find(const char *) const = 0;virtual int Find(const char *) const = 0;};};

Cannot instantiate abstract baseCannot instantiate abstract base Can declare pointers or references to abstract basesCan declare pointers or references to abstract bases

Must instead derive concrete type that implements Must instead derive concrete type that implements each pure virtual functioneach pure virtual function

Classes with Classes with only only pure virtual functions (no data pure virtual functions (no data members, no implementation code) often called members, no implementation code) often called pure abstract bases, protocol classespure abstract bases, protocol classes or or interfaces interfaces

Page 18: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Interfaces And Interfaces And ImplementationsImplementations Given an abstract interface, the most common way Given an abstract interface, the most common way

to associate an implementation with it isto associate an implementation with it isthrough inheritancethrough inheritance

Class FastString : public IFastString {...};Class FastString : public IFastString {...};

Implementation type must provide concrete Implementation type must provide concrete implementations of each interface methodimplementations of each interface method

Some mechanism needed to create instances of the Some mechanism needed to create instances of the implementation 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 function

Must 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 cannot Since the new operator is not used by the client, it cannot

call the delete operatorcall the delete operator

Page 19: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Exporting Via Abstract BasesExporting Via Abstract Bases

// faststringclient.h – common header between client/class// faststringclient.h – common header between client/class

// here’s the DLL-friendly abstract interface:// here’s the DLL-friendly abstract interface:struct struct IFastStringIFastString { { virtual void virtual void DeleteDelete() = 0;() = 0; virtual int Length() const = 0;virtual int Length() const = 0; virtual int Find(const char *sz) const = 0;virtual int Find(const char *sz) const = 0;};};

// and here’s the DLL-friendly factory function:// and here’s the DLL-friendly factory function:extern “C” boolextern “C” boolCreateInstanceCreateInstance(const char *pszClassName, // which class?(const char *pszClassName, // which class? const char *psz, // ctor argsconst char *psz, // ctor args IFastString **ppfs); // the objrefIFastString **ppfs); // the objref

Page 20: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Exporting Via Abstract BasesExporting Via Abstract Bases// faststring.h – private source file of class// faststring.h – private source file of class#include “faststringclient.h”#include “faststringclient.h”class FastString : public IFastString {class FastString : public IFastString {// normal prototype of FastString class + Delete// normal prototype of FastString class + Delete void Delete() { void Delete() { deletedelete this; } this; }};};

// component.cpp – private source file for entire DLL// component.cpp – private source file for entire DLL#include “faststring.h” // import FastString#include “faststring.h” // import FastString#include “fasterstring.h” // import FasterString (another class)#include “fasterstring.h” // import FasterString (another class)

bool CreateInstance(const char *pszClassName, bool CreateInstance(const char *pszClassName, const char *psz, IFastString **ppfs) {const char *psz, IFastString **ppfs) { *ppfs = 0;*ppfs = 0; if (strcmp(pszClassName, “FastString”) == 0) if (strcmp(pszClassName, “FastString”) == 0) *ppfs = static_cast<IFastString*>(*ppfs = static_cast<IFastString*>(newnew FastString(sz)); FastString(sz)); else if (strcmp(pszClassName, “FasterString”) == 0) else if (strcmp(pszClassName, “FasterString”) == 0) *ppfs = static_cast<IFastString*>(*ppfs = static_cast<IFastString*>(newnew FasterString(sz)); FasterString(sz)); return *ppfs != 0;return *ppfs != 0;}}

Page 21: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

m_textm_text

m_lengthm_length

vptrvptr FastString::DeleteFastString::Delete

FastString::LengthFastString::Length

FastString::FindFastString::Find

pfspfs

ClientClient ObjectObject

Exporting UsingExporting UsingAbstract BasesAbstract Bases

Page 22: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

bool LoadAndCreate(const char *szDLL, const char *sz,bool LoadAndCreate(const char *szDLL, const char *sz, IFastString **ppfs){IFastString **ppfs){ HINSTANCE h = LoadLibrary(szDLL);HINSTANCE h = LoadLibrary(szDLL); bool (*fp)(const char*, const char*, IFastString**);bool (*fp)(const char*, const char*, IFastString**); *((FARPROC*)&fp) = GetProcAddress(h, “CreateInstance”);*((FARPROC*)&fp) = GetProcAddress(h, “CreateInstance”); return fp(“FastString”, sz, ppfs);return fp(“FastString”, sz, ppfs);}}

Interfaces AndInterfaces AndPlug-compatibilityPlug-compatibility Note that a particular DLL can supply multiple implementations Note that a particular DLL can supply multiple implementations

of same interfaceof same interface CreateInstance(“SlowString”, “Hello!!”, &pfs);CreateInstance(“SlowString”, “Hello!!”, &pfs);

Due to simplicity of model, runtime selection ofDue to simplicity of model, runtime selection ofimplementation trivialimplementation trivial Explicitly load DLL and bind function addressExplicitly load DLL and bind function address

Page 23: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Interfaces And EvolutionInterfaces And Evolution

Previous slides alluded to interface remaining Previous slides alluded to interface remaining constant across versionsconstant across versions

Interface-based development mandates that new Interface-based development mandates that new functionality be exposed using additional interface functionality be exposed using additional interface Extended functionality provided by deriving fromExtended functionality provided by deriving from

existing interfaceexisting interface Orthogonal functionality provided by creating newOrthogonal functionality provided by creating new

sibling interfacesibling interface

Some technique needed for dynamically Some technique needed for dynamically interrogating an object for interface supportinterrogating an object for interface support Most languages support some sort of runtime cast Most languages support some sort of runtime cast

operation (e.g., C++’s dynamic_cast)operation (e.g., C++’s dynamic_cast)

Page 24: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

// faststringclient.h// faststringclient.hstruct IFastNFind : public IFastString {struct IFastNFind : public IFastString { virtual int FindN(const char *sz, int n) const = 0;virtual int FindN(const char *sz, int n) const = 0;};};

// faststringclient.cxx// faststringclient.cxx

int Find10thInstanceOfFoo(IFastString *pfs) {int Find10thInstanceOfFoo(IFastString *pfs) { IFastNFind *pfnf = 0;IFastNFind *pfnf = 0; if (pfnf = if (pfnf = dynamic_cast<IFastNFind *>dynamic_cast<IFastNFind *>(pfs)) {(pfs)) { return pfnf->FindN(“Foo”, 10);return pfnf->FindN(“Foo”, 10); }} elseelse // 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

Page 25: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

m_textm_text

m_lengthm_length

vptrvptr

FastString::DeleteFastString::Delete

FastString::LengthFastString::Length

FastString::FindFastString::Find

pfspfs

ClientClient ObjectObject

pfnfpfnfFastString::FindNFastString::FindN

Example: AddingExample: AddingExtended FunctionalityExtended Functionality

Page 26: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

// faststringclient.h// faststringclient.hstruct IPersistentObject {struct IPersistentObject { virtual void Delete(void) = 0;virtual void Delete(void) = 0; virtual bool Load(const char *sz) = 0;virtual bool Load(const char *sz) = 0; virtual bool Save(const char *sz) const = 0;virtual bool Save(const char *sz) const = 0;};};

// faststringclient.cxx// faststringclient.cxx

bool SaveString(IFastString *pfs) {bool SaveString(IFastString *pfs) { IPersistentObject *ppo = 0;IPersistentObject *ppo = 0; if (ppo = if (ppo = dynamic_cast<IPersistentObject*>dynamic_cast<IPersistentObject*>(pfs)) {(pfs)) { return ppo->Save(“Autoexec.bat”);return ppo->Save(“Autoexec.bat”); }} elseelse return false; // cannot save...return false; // cannot save...}}

Example: Adding Example: Adding Orthogonal FunctionalityOrthogonal Functionality Add support for generic persistenceAdd support for generic persistence

Page 27: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

m_textm_text

m_lengthm_length

vptrvptr

FastString::DeleteFastString::Delete

FastString::LengthFastString::Length

FastString::FindFastString::Find

pfspfs

Client Object

vptrvptr

FastString::DeleteFastString::Delete

FastString::LoadFastString::Load

ppoppo

FastString::SaveFastString::Save

Example: Adding Example: Adding Orthogonal FunctionalityOrthogonal Functionality

Page 28: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Fixing Interface-Based Fixing Interface-Based Programming In C++Programming In C++ The dynamic_cast operator has several problems The dynamic_cast operator has several problems

that must be addressedthat must be addressed 1) Its implementation is non-standard across compilers1) Its implementation is non-standard across compilers 2) There is no standard runtime representation2) There is no standard runtime representation

for the typenamefor the typename 3) Two parties may choose colliding typenames3) Two parties may choose colliding typenames

Can solve #1 by adding yet another well-known Can solve #1 by adding yet another well-known abstract method to each interface (a la Delete)abstract method to each interface (a la Delete)

#2 and #3 solved by using a well-known #2 and #3 solved by using a well-known namespace/type format for identifying interfacesnamespace/type format for identifying interfaces UUIDs from OSF DCE are compact (128 bit), efficient and UUIDs from OSF DCE are compact (128 bit), efficient and

guarantee uniquenessguarantee uniqueness UUIDs are basically big, unique integers!UUIDs are basically big, unique integers!

Page 29: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

QueryInterfaceQueryInterface

COM programmers use the well-known abstract COM programmers use the well-known abstract method (QueryInterface) in lieu of dynamic_castmethod (QueryInterface) in lieu of dynamic_cast

virtual HRESULT _stdcall virtual HRESULT _stdcall

QueryInterface(REFIID riid,// the requested UUIDQueryInterface(REFIID riid,// the requested UUID

void **ppv // the resultant objrefvoid **ppv // the resultant objref

) = 0;) = 0;

Returns status code indicating success (S_OK) or Returns status code indicating success (S_OK) or failure (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 name VC-specific __declspec(uuid) conjoins COM/C++ namesVC-specific __declspec(uuid) conjoins COM/C++ names

Page 30: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

void UseAsTelephone(ICalculator *pCalc) {void UseAsTelephone(ICalculator *pCalc) { ITelephone *pPhone = 0;ITelephone *pPhone = 0; pPhone = dynamic_cast<ITelephone*>(pCalc);pPhone = dynamic_cast<ITelephone*>(pCalc); if (pPhone) {if (pPhone) { // use pPhone// use pPhone : : :: : :

void UseAsTelephone(ICalculator *pCalc) {void UseAsTelephone(ICalculator *pCalc) { ITelephone *pPhone = 0;ITelephone *pPhone = 0; HRESULT hr = pCalc->QueryInterface(IID_ITelephone,HRESULT hr = pCalc->QueryInterface(IID_ITelephone, (void**)&pPhone);(void**)&pPhone); if (hr == S_OK) {if (hr == S_OK) { // use pPhone// use pPhone : : :: : :

QueryInterface As A Better QueryInterface As A Better Dynamic CastDynamic Cast

Page 31: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

ICalculator *pCalc1 = CreateCalc();ICalculator *pCalc1 = CreateCalc();ITelephone *pPhone1 = CreatePhone();ITelephone *pPhone1 = CreatePhone();ICalculator *pCalc2 = dynamic_cast<ICalculator*>(pPhone1);ICalculator *pCalc2 = dynamic_cast<ICalculator*>(pPhone1);ICalculator *pCalc3 = CreateCalc();ICalculator *pCalc3 = CreateCalc();

pPhone1->Dial(pCalc1->Add(pCalc2->Add(pCalc3->Add(2))));pPhone1->Dial(pCalc1->Add(pCalc2->Add(pCalc3->Add(2))));

pCalc1->Delete(); // assume interfaces have Delete pCalc1->Delete(); // assume interfaces have Delete pCalc2->Delete(); // per earlier discussionpCalc2->Delete(); // per earlier discussionpPhone1->Delete(); pPhone1->Delete();

Fixing Interface-Based Fixing Interface-Based Programming In C++Programming In C++ Previous examples used a “Delete” method to allow Previous examples used a “Delete” method to allow

client to destroy objectclient to destroy object Requires client to remember which references point to Requires client to remember which references point to

which objects to ensure each object deleted exactly oncewhich objects to ensure each object deleted exactly once

Page 32: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Fixing Interface-Based Fixing Interface-Based Programming In C++Programming In C++ COM solves the “Delete” problem withCOM solves the “Delete” problem with

reference countingreference counting Clients blindly “Delete” each reference, not each objectClients blindly “Delete” each reference, not each object

Objects can track number of extant references and Objects can track number of extant references and auto-delete when count reaches zeroauto-delete when count reaches zero Requires 100% compliance with ref. counting rulesRequires 100% compliance with ref. counting rules

All operations that return interface pointers must All operations that return interface pointers must increment the interface pointer’s reference countincrement the interface pointer’s reference count QueryInterface, CreateInstance, etc.QueryInterface, CreateInstance, etc.

Clients must inform object that a particular interface Clients must inform object that a particular interface pointer has been destroyed using well-known methodpointer has been destroyed using well-known method Virtual ULONG _stdcall Release( ) = 0;Virtual ULONG _stdcall Release( ) = 0;

Page 33: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

ICalculator *pCalc1 = CreateCalc();ICalculator *pCalc1 = CreateCalc();ITelephone *pPhone1 = CreatePhone();ITelephone *pPhone1 = CreatePhone();ICalculator *pCalc2 = 0;ICalculator *pCalc2 = 0;ICalculator *pCalc3 = CreateCalc();ICalculator *pCalc3 = CreateCalc();ITelephone *pPhone2 = 0;ITelephone *pPhone2 = 0;ICalculator *pCalc4 = 0;ICalculator *pCalc4 = 0;

pPhone1->QueryInterface(IID_ICalculator,(void**)&pCalc2);pPhone1->QueryInterface(IID_ICalculator,(void**)&pCalc2);pCalc3->QueryInterface(IID_ITelephone,(void**)&pPhone2);pCalc3->QueryInterface(IID_ITelephone,(void**)&pPhone2);pCalc1->QueryInterface(IID_ICalculator, (void**)&pCalc4);pCalc1->QueryInterface(IID_ICalculator, (void**)&pCalc4);

pPhone1->Dial(pCalc1->Add(pCalc2->Add(pCalc3->Add(2))));pPhone1->Dial(pCalc1->Add(pCalc2->Add(pCalc3->Add(2))));

pCalc1->Release(); pCalc4->Release(); pCalc1->Release(); pCalc4->Release(); pCalc2->Release(); pPhone1->Release(); pCalc2->Release(); pPhone1->Release(); pCalc3->Release(); pPhone2->Release(); pCalc3->Release(); pPhone2->Release();

Reference Counting BasicsReference Counting Basics

Page 34: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

extern const IID IID_IUnknown;extern const IID IID_IUnknown;struct IUnknown {struct IUnknown { virtual HRESULT STDMETHODCALLTYPE QueryInterface(virtual HRESULT STDMETHODCALLTYPE QueryInterface( const IID& riid, void **ppv) = 0;const IID& riid, void **ppv) = 0; virtual ULONG STDMETHODCALLTYPE AddRef( ) = 0;virtual ULONG STDMETHODCALLTYPE AddRef( ) = 0; virtual ULONG STDMETHODCALLTYPE Release( ) = 0;virtual ULONG STDMETHODCALLTYPE Release( ) = 0;};};

IUnknownIUnknown

The three core abstract operations (QueryInterface, The three core abstract operations (QueryInterface, AddRef, and Release) comprise the core interfaceAddRef, and Release) comprise the core interfaceof COM, IUnknownof COM, IUnknown

All COM interfaces must extend IUnknownAll COM interfaces must extend IUnknown All COM objects must implement IUnknownAll COM objects must implement IUnknown

Page 35: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Com Interfaces In NatureCom Interfaces In Nature

Represented as pure abstract baseRepresented as pure abstract baseclasses in C++classes in C++ All methods are pure virtualAll methods are pure virtual Never any code, only signatureNever any code, only signature Format of C++ vtable/vptr defines expected stack frameFormat of C++ vtable/vptr defines expected stack frame

Represented directly as interfaces in JavaRepresented directly as interfaces in Java Represented as Non-Creatable classes inRepresented as Non-Creatable classes in

Visual BasicVisual Basic Uniform binary representation independent of Uniform binary representation independent of

how you built the objecthow you built the object Identified uniquely by a 128-bit Interface ID (IID)Identified uniquely by a 128-bit Interface ID (IID)

Page 36: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Com Interfaces In NatureCom Interfaces In Nature

COM interfaces are described first inCOM interfaces are described first inCOM IDLCOM IDL

COM 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++ interface IDL compiler directly emits C/C++ interface definitions as source codedefinitions as source code

IDL compiler emits tokenized type library IDL compiler emits tokenized type library containing (most) of original contents in an containing (most) of original contents in an easily parsed formateasily parsed format

JavaJava™™/Visual Basic/Visual Basic®® pick up mappings from pick up mappings from type librarytype library

Page 37: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Foo.idlFoo.idlIDLIDL

DescriptionDescriptionof Foo interfacesof Foo interfaces

and 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

SupportSupport

Foo.tlbFoo.tlbBinary Binary

DescriptionsDescriptions

MIDL.EXEMIDL.EXE *.java*.javaJava Java

DefinitionsDefinitions

JACTIVEX.EXEJACTIVEX.EXE

COM IDLCOM IDL

Page 38: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

COM IDLCOM IDL

All 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 scope Required 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 definition

Can import std interface suiteCan import std interface suite WTYPES.IDL - basic data typesWTYPES.IDL - basic data types UNKNWN.IDL - core type interfacesUNKNWN.IDL - core type interfaces OBJIDL.IDL - core infrastructure itfsOBJIDL.IDL - core infrastructure itfs OLEIDL.IDL - OLE itfsOLEIDL.IDL - OLE itfs OAIDL.IDL - Automation itfsOAIDL.IDL - Automation itfs OCIDL.IDL - ActiveX Control itfsOCIDL.IDL - ActiveX Control itfs

Page 39: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

[ uuid(DEFACED1-0229-2552-1D11-ABBADABBAD00), object ][ uuid(DEFACED1-0229-2552-1D11-ABBADABBAD00), object ]interface interface ICalculator : IDesktopDevice ICalculator : IDesktopDevice {{ import “dd.idl”; // bring in IDesktopDevice import “dd.idl”; // bring in IDesktopDevice HRESULT Clear(void);HRESULT Clear(void); HRESULT Add([in] short n); // n sent to objectHRESULT Add([in] short n); // n sent to object HRESULT GetSum([out] short *pn); // *pn sent to callerHRESULT GetSum([out] short *pn); // *pn sent to caller}}[ [ uuid(DEFACED2-0229-2552-1D11-ABBADABBAD00), uuid(DEFACED2-0229-2552-1D11-ABBADABBAD00), helpstring(“My Datatypes”) helpstring(“My Datatypes”) ]]library CalcTypes {library CalcTypes { importlib(“stdole32.tlb”); // requiredimportlib(“stdole32.tlb”); // required interface ICalculator; // cause TLB inclusioninterface ICalculator; // cause TLB inclusion}}

CalcTypes.idlCalcTypes.idl

COM IDLCOM IDL

Page 40: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

COM IDL - C++ MappingCOM IDL - C++ Mapping

#include “dd.h”#include “dd.h”extern const IID IID_ICalculator;extern const IID IID_ICalculator;struct struct __declspec(uuid(“DEFACED1-0229-2552-1D11-ABBADABBAD00”)) __declspec(uuid(“DEFACED1-0229-2552-1D11-ABBADABBAD00”)) ICalculator : public IDesktopDevice {ICalculator : public IDesktopDevice { virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0; virtual HRESULT STDMETHODCALLTYPE Add(short n) = 0;virtual HRESULT STDMETHODCALLTYPE Add(short n) = 0; virtual HRESULT STDMETHODCALLTYPE GetSum(short *pn) = 0;virtual HRESULT STDMETHODCALLTYPE GetSum(short *pn) = 0;};};extern const GUID LIBID_CalcTypes;extern const GUID LIBID_CalcTypes;

const IID IID_ICalculator = {0xDEFACED1, 0x0229, 0x2552,const IID IID_ICalculator = {0xDEFACED1, 0x0229, 0x2552, { 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } };{ 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00 } };const GUID LIBID_CalcTypes = {0xDEFACED2, 0x0229, 0x2552,const GUID LIBID_CalcTypes = {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

Page 41: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

COM IDL – Java/VB MappingCOM IDL – Java/VB Mapping

package CalcTypes; // library namepackage CalcTypes; // library name/**@com.interface(iid=DEFACED1-0229-2552-1D11-ABBADABBAD00)*//**@com.interface(iid=DEFACED1-0229-2552-1D11-ABBADABBAD00)*/interface ICalculator extends IDesktopDevice {interface ICalculator extends IDesktopDevice { public void Clear( );public void Clear( ); public void Add(short n);public void Add(short n); public void GetSum(short [] pn); // array of length 1public void GetSum(short [] pn); // array of length 1 public static com.ms.com._Guid iid =public static com.ms.com._Guid iid = new com.ms.com._Guid(0xDEFACED1, 0x0229, 0x2552,new com.ms.com._Guid(0xDEFACED1, 0x0229, 0x2552, 0x1D, 0x11, 0xAB, 0xBA, 0x1D, 0x11, 0xAB, 0xBA, 0xDA, 0xBB, 0xAD, 0x00);0xDA, 0xBB, 0xAD, 0x00);}}

CalcTypes.javaCalcTypes.java

Public Sub Clear( )Public Sub Clear( )Public Sub Add(ByVal n As Integer)Public Sub Add(ByVal n As Integer)Public Sub GetSum(ByRef pn As Integer)Public Sub GetSum(ByRef pn As Integer)

CalcTypes.clsCalcTypes.cls

Page 42: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

particular valueparticular valueresres

Severity (31)Severity (31) Facility (27-16)Facility (27-16) Code (15-0)Code (15-0)

0 -> Success0 -> Success1 -> Failure1 -> Failure

FACILITY_NULLFACILITY_NULLFACILITY_ITFFACILITY_ITFFACILITY_STORAGEFACILITY_STORAGEFACILITY_DISPATCHFACILITY_DISPATCHFACILITY_WINDOWSFACILITY_WINDOWSFACILITY_RPCFACILITY_RPC

COM And Error HandlingCOM And Error Handling

COM (today) doesn’t support typed C++ or Java-COM (today) doesn’t support typed C++ or Java-style exceptionsstyle exceptions

All (remotable) methods must return a standard 32-All (remotable) methods must return a standard 32-bit error code called an HRESULTbit error code called an HRESULT Mapped to exception in higher-level languagesMapped to exception in higher-level languages Overloaded to indicate invocation errors from proxiesOverloaded to indicate invocation errors from proxies

Page 43: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

HRESULTsHRESULTs HRESULT names indicate severity and facilityHRESULT names indicate severity and facility

<FACILITY>_<SEVERITY>_<CODE><FACILITY>_<SEVERITY>_<CODE> DISP_E_EXCEPTIONDISP_E_EXCEPTION STG_S_CONVERTEDSTG_S_CONVERTED

FACILITY_NULL codes are implicitFACILITY_NULL codes are implicit <SEVERITY>_<CODE><SEVERITY>_<CODE> S_OKS_OK S_FALSES_FALSE E_FAILE_FAIL E_NOTIMPLE_NOTIMPL E_OUTOFMEMORYE_OUTOFMEMORY E_INVALIDARGE_INVALIDARG E_UNEXPECTEDE_UNEXPECTED

Can use FormatMessage API to lookup human-readable Can use FormatMessage API to lookup human-readable description at runtimedescription at runtime

Page 44: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

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 IntegerInteger

ScriptScript

NoNo

YesYes

NoNo

YesYes

NoNo

NoNo

NoNo

NoNo

YesYes

YesYes

NoNo

YesYes

NoNo

COM Data TypesCOM Data Types

Page 45: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

bytebyte

booleanboolean

VARIANT_BOOLVARIANT_BOOL

IDLIDL C++C++ JavaJava

BYTEBYTE

unsigned charunsigned char

longlong

VARIANT_BOOLVARIANT_BOOL

charchar

intint

booleanboolean

unsigned charunsigned char bytebyte

Visual BasicVisual Basic

N/AN/A

LongLong

BooleanBoolean

ByteByte

BSTRBSTR

VARIANTVARIANT

BSTRBSTR java.lang.Stringjava.lang.String

VARIANTVARIANT com.ms.com.Variantcom.ms.com.Variant

StringString

VariantVariant

CYCY longlong intint CurrencyCurrency

DATEDATE

enumenum

doubledouble doubledouble

enumenum intint

DateDate

EnumEnum

Typed ObjRefTyped ObjRef IFoo *IFoo * interface IFoointerface IFoo IFooIFoo

structstruct structstruct final classfinal class TypeType

unionunion

C-style ArrayC-style 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

Page 46: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

struct MESSAGE { VARIANT_BOOL b; long n; };struct MESSAGE { VARIANT_BOOL b; long n; };[ uuid(03C20B33-C942-11d1-926D-006008026FEA), object ][ uuid(03C20B33-C942-11d1-926D-006008026FEA), object ]interface IAnsweringMachine : IUnknown {interface IAnsweringMachine : IUnknown { HRESULT TakeAMessage([in] struct MESSAGE *pmsg);HRESULT TakeAMessage([in] struct MESSAGE *pmsg); [propput] HRESULT OutboundMessage([in] long msg);[propput] HRESULT OutboundMessage([in] long msg); [propget] HRESULT OutboundMessage([out, [propget] HRESULT OutboundMessage([out, retvalretval] long *p);] long *p);}}

public final class MESSAGE { public final class MESSAGE { public boolean b; public int n; public boolean b; public int n; }}public interface IAnsweringMachine extends IUnknown public interface IAnsweringMachine extends IUnknown {{ public void TakeAMessage(MESSAGE msg);public void TakeAMessage(MESSAGE msg); public void putOutboundMessage(int);public void putOutboundMessage(int); public int getOutboundMessage();public int getOutboundMessage();}}

ExampleExample

Page 47: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

Where Are We?Where Are We?

Clients program in terms of abstract data Clients program in terms of abstract data types called interfacestypes called interfaces

Clients can load method code dynamically Clients can load method code dynamically without concern for C++ compiler without concern for C++ compiler incompatibilitiesincompatibilities

Clients interrogate objects for extended Clients interrogate objects for extended functionality via RTTI-like constructsfunctionality via RTTI-like constructs

Clients notify objects when references are Clients notify objects when references are duplicated or destroyedduplicated or destroyed

Welcome to the Component Object Model!Welcome to the Component Object Model!

Page 48: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.

ReferencesReferences

Programming Dist Apps With Visual Basic Programming Dist Apps With Visual Basic and COMand COM Ted Pattison, Microsoft PressTed Pattison, Microsoft Press

Inside COMInside COM Dale Rogerson, Microsoft PressDale Rogerson, 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, DevelopMentorDevelopMentor http://www.develop.comhttp://www.develop.com

DCOM Mailing ListDCOM Mailing List http://discuss.microsoft.comhttp://discuss.microsoft.com

Page 49: Fundamentals Of COM(+) (Part 1) Don Box Cofounder DevelopMentor  11-203.