You are on page 1of 19

COM / DCOM / COM+

Cosimo Stufano

Evolución de COM / DCOM / COM+

l COM (Component Object Model)


es el resultado de la evolución y
convergencia de dos tecnologías:
Ø La comunicación inter-procesos en
los ambientes Windows de Microsoft.
Ø El desarrollo de un mecanismo para
la invocación de procedimientos
remotos (RPC: Remote Procedure
Calls) por parte de la OSF como
parte de un ambiente de
computación distribuida (DCE).

1
Evolución de COM+
Computació
Computación
DDE Clipboard
1987 1987 distribuida
1980s

OLE 1 Open Softare Foundation


1992 Distribited Computing Enviroment
Remote Procedure Calls

COM (OSF DCE RPC)


1992
1995

DCOM COM+
1996 1999

¿COM, DCOM o COM+?

l COM permite interacció


interacción entre
componentes COM que residen en un
computador
l DCOM (Distributed COM) agrega la
posibilidad de que estos objetos este
distribuidos en la red
l COM+ agrega al modelo de objetos una
variedad de servicios para el desarrollo de
aplicaciones empresariales

2
¿ Que es COM?
l COM es una especificación.
l COM es una porción de código que
forma parte de varios sistemas
operativos.
l COM es una filosofía para el
desarrollo de aplicaciones.
l COM es un estándar binario para
la construcción de componentes.

¿Que es un componente COM?

l Es un contenedor binario
l Contiene el código de una o mas clases de
objetos
l Cada clase puede tener una o mas
interfaces
l COM expone o publica estas interfaces para
que puedan ser usadas por otras
aplicaciones.
aplicaciones.
l Una aplicació
aplicación puede usar componentes
COM. independientemente del lenguaje en
que fueron escritos.
escritos.

3
¿Que es un componente COM?

IUnknown

IClassFactory
Class
Factory
Cliente

Objeto Registro
Envoltorio
Componente

Interfaces
l Las aplicaciones accesan el
contenido de los componentes
COM mediante sus interfaces
l Las interfaces describen los
métodos disponibles y sus
pará
parámetros
l Las interfaces se identifican
mediante núnúmeros unicos de 128
bits llamados GUID o UUID.

4
GUIDs, UUIDs, IIDs, etc.
l Los identificadores de interfaces se
escriben de la forma
{B45E9146-3349-4F77-9151-2BF646CB9CAF}
l Dos interfaces bien conocidas son:
Ø IUnknown
{00000000-0000-0000-C000-000000000046}
Ø IClassFactory
{00000001-0000-0000-C000-000000000046}
l Estas interfaces se discutiran en detalle
más adelante

Tipos de componentes COM


l In Process
l Locales
l Remotos

Programa Programa Programa

Invocació
Invocación

Invocació
Invocación Componente

Componente

5
Infraestructura COM
l El sistema operativo debe proveer
funciones para clientes y servidores.
servidores.
Ø Para clientes:
clientes: Activació
Activación de objetos
Ø Para servidores:
servidores: Facilidades para publicar
sus interfaces
l Servicios de localizació
localización de componetes:
componetes:
el registro
l Servicios RPC transparentes
l Mecanismos para control de aplicaciones
y asignació
asignación de memoria

Definición de Interfaces (IDL)


l Se requiere un mecanismo para definir
interfaces independientes del lenguaje de
programacion.
programacion.
l Para esto se utiliza un IDL (Interface
(Interface
Definition Language)
Language)
l IDL no es parte de COM
l Se compila com MIDL

import “unknown.idl
unknown.idl”
”;
[ object, uuid(1000001
uuid(1000001-
-0000-
0000- 0000-
0000-0000-
0000-000000000001) ]
interface ISum : IUnknown
{
HRESULT Sum ([in] int x, [in] int y, [out, retval]
retval] int*
int* retval);
retval);
};

6
Funciones COM
l Todas las funciones de COM comienzan
con el prefijo Co.
l Estas funciones son parte del sistema
operativo.
l Las principales funciones son:
Ø CoInitialize(NULL);
Ø CoCreateInstance(clsid, pUnkOuter,
grfContext, iid, ppvObj);
Ø CoUninitialize();

La interface IUnknown
l Todo componente COM debe
implementar al menos esta
inteface.
inteface.
l Esta interface debe contener estos
tres metodos:
metodos:
Ø QueryInterface (IID,ppv
(IID,ppv);
);
Ø AddRef ();
Ø Release ();

7
QueryInterface (iid, ppv);
l Permite interrogar a un componete
para determinar si implementa
cierta interface.
l Debe cumplir las siguientes reglas
Ø Consistencia
Ø Ser está
estática
Ø Ser reflexiva
Ø Ser simé
simétrica
Ø Ser transitiva

La interface IClassFactory
l Para activar un componente,
componente, COM
debe conocer como crearlo.
crearlo. Para esto
el componente debe contener un objeto
fábrica que implemente IClassFactory
l IClassFactory contiene dos métodos:
todos:
Ø CreateInstance (pUnkOuter,
pUnkOuter, riid,
riid, ppv);
ppv);
Ø LockServer (fLock);
fLock);

8
Un componente COM
IUnknown

IClassFactory
Class
Factory

IUnknown

Objeto Registro
Envoltorio
Componente

Un ejemplo
l El ejemplo esta en C++
l Consta de:
Ø Un cliente que usa el servidor
Ø Un componente servidor In Process
que implementa la operació
operación suma
Ø El servidor consta de:
Ø Una clase MySum
Ø Una clase Cfactory
Ø Dos funciones DLL
Ø Un archivo para registrarlo

9
El cliente (1)
/ client.cpp
client.cpp
#include <iostream
<iostream.h>
.h>
#include "component.h" // Generated by MIDL

// {10000002-
{10000002-0000-
0000-0000-
0000-0000-
0000-000000000001}
const CLSID CLSID_MySum
CLSID_MySum =
{0x10000002,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};
{0x10000002,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};

void main()
{
cout << "Client: Calling CoInitialize()"
CoInitialize()" << endl;
endl;
HRESULT hr = CoInitialize(NULL);
CoInitialize(NULL);
if(FAILED(hr))
cout << "CoInitialize
"CoInitialize failed" << endl;
endl;

IUnknown*
IUnknown* pUnknown;
pUnknown;
ISum*
ISum* pSum;
pSum;

cout << "Client: Calling CoCreateInstance()"


CoCreateInstance()" << endl;
endl;
hr = CoCreateInstance(CLSID_
CoCreateInstance(CLSID_MySum
MySum,
, NULL,
CLSCTX_INPROC_SERVER, IID_IUnknown
IID_IUnknown,
, (void**)&pUnknown
(void**)&pUnknown);
);
if(FAILED(hr))
cout << "CoCreateInstance
"CoCreateInstance failed" << endl;
endl;

El cliente (2)
cout << "Client: Calling QueryInterface()
QueryInterface() for ISum on " <<
pUnknown << endl;
endl;
hr = pUnknown-
pUnknown->QueryInterface(IID_
QueryInterface(IID_ISum
ISum,
, (void**)&pSum
(void**)&pSum);
);
if(FAILED(hr))
cout << "IID_ISum
"IID_ISum not supported" << endl;
endl;

hr = pUnknown-
pUnknown->Release();
cout << "Client: Calling pUnknown-
pUnknown->Release() reference count = "
<< hr << endl;
endl;

int sum;
hr = pSum-
pSum->Sum(2, 3, &sum);
if(SUCCEEDED(hr))
cout << "Client: Calling Sum(2, 3) = " << sum << endl;
endl;

hr = pSum-
pSum->Release();
cout << "Client: Calling pSum-
pSum->Release() reference count = " <<
hr << endl;
endl;

cout << "Client: Calling CoUninitialize()"


CoUninitialize()" << endl;
endl;
CoUninitialize();
CoUninitialize();
}

10
Funciones DLL
l El componente debe implementar dos
funciones DLL:
Ø DllGetClassObject (REFCLSID clsid, REFIID riid, void** ppv);
Ø DllCanUnloadNow();

l La primera permite obtener un apuntador a


IClassFactory
l La segunda permite a COM determinar si
puede o no descargar el DLL de memoria

Funciones DLL

l Las funciones DLL deben declararse en


un archivo DEF como sigue:
sigue:

; component.def
LIBRARY component.dll
component.dll
DESCRIPTION 'COM component example'
EXPORTS
DllGetClassObject @2 PRIVATE
DllCanUnloadNow @3 PRIVATE

11
El componente - clase MySum
// component.cpp
#include <iostream.h> // For cout
#include "component.h" // Generated by MIDL

// {10000002-0000-0000-0000-000000000001}
const CLSID CLSID_MySum =
{0x10000002,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};

long g_cComponents = 0;
long g_cServerLocks = 0;

class CMySum : public ISum


{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

// ISum
HRESULT __stdcall Sum(int x, int y, int* retval);

CMySum() : m_cRef(1) { g_cComponents++; }


~CMySum() { cout << "Component: CMySum::~CMySum()" << endl,
g_cComponents--; }

private:
ULONG m_cRef;
};

MySum – Interface IUnknown


ULONG CMySum::AddRef()
{
cout << "Component: CMySum::AddRef() m_cRef = " << m_cRef + 1 << endl;
return ++m_cRef;
}
ULONG CMySum::Release()
{
cout << "Component: CMySum::Release() m_cRef = " << m_cRef - 1 << endl;
if(--m_cRef != 0) return m_cRef;
delete this;
return 0;
}
HRESULT CMySum::QueryInterface(REFIID iid, void** ppv)
{
if(iid == IID_IUnknown) {
cout << "Component: CMySum::QueryInterface() for IUnknown returning "
<< this << endl;
*ppv = (IUnknown*)this;
}
else if(iid == IID_ISum) {
cout << "Component: CMySum::QueryInterface() for ISum returning " <<
this << endl;
*ppv = (ISum*)this;
}
else {
*ppv = NULL; return E_NOINTERFACE;}
AddRef();
return S_OK;
}

12
MySum – Interface ISUM

HRESULT CMySum::Sum(int x, int y, int* retval)


{
cout << "Component: CMySum::Sum() " << x << " + " << y << " = "
<< x + y << endl;
*retval = x + y;
return S_OK;
}

Clase CFactory
class CFactory : public IClassFactory
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

// IClassFactory
HRESULT __stdcall CreateInstance(IUnknown *pUnknownOuter,
REFIID iid, void** ppv);
HRESULT __stdcall LockServer(BOOL bLock);

CFactory() : m_cRef(1) { }
~CFactory() { }

private:
ULONG m_cRef;
};

13
CFactory – Interface IUnknown
ULONG CFactory::AddRef()
{
cout << "Component: CFactory::AddRef() m_cRef = " << m_cRef + 1 << endl;
return ++m_cRef;
}
ULONG CFactory::Release()
{
cout << "Component: CFactory::Release() m_cRef = " << m_cRef - 1 << endl;
if(--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}

HRESULT CFactory::QueryInterface(REFIID iid, void** ppv)


{
if((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
cout << "Component: CFactory::QueryInteface() for IUnknown or
IClassFactory " << this << endl;
*ppv = (IClassFactory *)this;
}
else {
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}

Cfactory – Interface IClassFactory


HRESULT CFactory::CreateInstance(IUnknown *pUnknownOuter, REFIID iid,
void** ppv)
{
if(pUnknownOuter != NULL)
return CLASS_E_NOAGGREGATION;

CMySum *pMySum = new CMySum;


cout << "Component: CFactory::CreateInstance() " << pMySum <<
endl;

if(pMySum == NULL)
return E_OUTOFMEMORY;

// QueryInterface probably for IID_IUNKNOWN


HRESULT hr = pMySum->QueryInterface(iid, ppv);
pMySum->Release();
return hr;
}

HRESULT CFactory::LockServer(BOOL bLock)


{
if(bLock)
g_cServerLocks++;
else
g_cServerLocks--;
return S_OK;
}

14
Componente – Funciones DLL
HRESULT __stdcall DllCanUnloadNow()
{
cout << "Component: DllCanUnloadNow() " << (g_cServerLocks == 0 &&
g_cComponents == 0 ? "Yes" : "No") << endl;
if(g_cServerLocks == 0 && g_cComponents == 0)
return S_OK;
else
return S_FALSE;
}

HRESULT __stdcall DllGetClassObject(REFCLSID clsid, REFIID iid, void** ppv)


{
cout << "Component: DllGetClassObject" << endl;

if(clsid != CLSID_MySum)
return CLASS_E_CLASSNOTAVAILABLE;

CFactory* pFactory = new CFactory;


if(pFactory == NULL)
return E_OUTOFMEMORY;

// QueryInterface probably for IClassFactory


HRESULT hr = pFactory->QueryInterface(iid, ppv);
pFactory->Release();
return hr;
}

Registro del componente


l Para registrar el componente se
tienen dos alternativas:
alternativas:
Ø Usar un archivo .reg como el mostrado
abajo
Ø Agregar al componente la habilidad de
registrarse.
registrarse.
REGEDIT4

[HKEY_CLASSES_ROOT\CLSID\{10000002-0000-0000-0000-000000000001}]
@=“Ejemplo de COM"

[HKEY_CLASSES_ROOT\CLSID\{10000002-0000-0000-0000-00000000001}\InprocServer32]
@="C:\\Program Files\\DevStudio\\MyProjects\\Component\\Debug\\Component.dll"

15
ActiveX
l Definiciones
Ø Un término de mercadeo de Microsoft.
Ø Un término de Microsoft para identificar
sus tecnologías que pueden aplicarse al
Internet.
Ø Un componente COM que implementa
IUnknown y tiene capacidad para auto-
registrarse.
Ø El nuevo nombre de los controles OLE.

COM, OLE y ActiveX


ActiveX

Documentos
Activació
Activación en sito
(Edició
Edición visual) Controles
Linking
Embedding

Drag-
Drag-and Drop
OLE
Macros
Transferencia de datos uniforme COM

Almacenamiento persistente Monikers Automatizació


Automatización

El Modelo de Objetos Componentes (COM)

16
Mecanismos de re-utilización COM
l Como las interfaces en los componetes
COM son inmutables.
inmutables.
l Si se desea incorporar la funcionalidad
de un Componente COM se debe usar
inclusió
inclusión o agregació
agregación

Agregador Contenedor

Objeto Objeto

COM+
l Integra COM con servicios para el
desarrollo de aplicaciones empresariales.
empresariales.
l En cierto modo COM+ es la fusió
fusión de
COM, MTS (Microsoft Transaction Server)
y otros componentes.
componentes.
l Ademas de métodos,
todos, los componentes
tiene ahora un contexto y atributos.
atributos.
l COM+ examina el contexto y determina si
deben ejecutarse acciones antes o
despues de invocar al objeto.
objeto.

17
Componentes COM+

IUnknown

Contexto

Atributos
Cliente

Servidor

Beneficios de COM+
l Simplificació
Simplificación en el desarrollo de
aplicació
aplicaciónes:
nes: se reduce al mínimo la
infraestructura de programació
programación.
l Modelo simple y escalable:
escalable: los servidores
hacen casi todo el trabajo
l Arquitectura simple y extensible: se
agrega funcionalidad enriqueciendo el
contexto no creando nuevas API

18
Interceptores
l Para procesar el contexto,
contexto, COM+
intercepta las invocaciones a los objetos
para realizara pre-
pre- y post-
post- procesamiento.
procesamiento.
Thread
Cliente procesador Servidor
del contexto

Cliente Servidor
Transacció
Transacción

DTC Data

Funcionalidad de COM+
l Desarrollo de servidores
l Servicios transaccionales
l Seguridad
l Administración
l Colas de componentes (procesamiento
diferido)
l Manejo de eventos
l Balance de carga

19