Professional Documents
Culture Documents
1 Introducción
DCOM (Distributed 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 y los esfuerzos del la OSF (Open Software Foundation) para desarrollar un ambiente
de computación distribuido (DCE, Distributed Computing Environment), en particular un
protocolo para la invocación de procesos remotos (RPC, Remote Procedure Calls). La Figura 1
Computación
DDE Clipboard
1987 1987 distribuida
1980s
DCOM COM+
1996 1999
1 Evolución de COM
muestra la evolución de DCOM
Los primeros computadores personales tenían capacidades limitadas y empleaban
sistemas operativos simples que solo podían ejecutar un proceso (programa) a la vez. Con el
desarrollo de procesadores más poderosos y de sistemas operativos más sofisticados se hizo
posible la ejecución de varios procesos de forma (aparentemente) simultánea incorporando
técnicas de tiempo compartido. Debido a la modalidad de uso de los computadores personales
(interacción directa hombre-máquina) pronto se sintió la necesidad de contar con mecanismos de
intercambio de información entre procesos.
Los primeros intentos de ofrecer comunicación entre procesos en los ambientes Windows
1
fueron el DDE (Dynamic Data Exchange) y el Clipboard. El DDE era un mecanismo de
intercambio de mensajes que resultó complejo para los programadores y muy pocas aplicaciones
lo usaron exitosamente. El Clipboard, por otra parte, permitió a los usuarios de una forma simple
la creación de documentos compuestos, es decir, con diferentes tipos de contenidos generados
por diversos procesos.
La principal limitación del Clipboard es que los documentos creados son estáticos: si
cualquiera de los elementos de un documento compuesto cambia, se deberá modificar el
documento compuesto manualmente. Para atacar este problema, Microsoft introdujo en 1992 la
tecnología OLE (Object Linking and Embedding). OLE introduce los conceptos de objeto y
componente, acordes con los paradigmas modernos de programación.
Por otra parte la OSF se estableció en los años 1980s como un consorcio de empresas del
ramo de tecnologías de información con la misión de definir estándares independientes en el
área. DCE es de los estándares propuestos por la OSF cuyo objetivo es la de proveer un ambiente
para el desarrollo de sistemas distribuidos. Uno de los componentes de DCE es una
especificación para la comunicación entre computadores. Esta especificación, conocida como
RPC, permite que aplicaciones en computadores diferentes se comuniquen.
La integración de COM y RPC dió origen a DCOM. Este último permite crear
aplicaciones cuyos componentes no necesariamente residen en un computador sino que pueden
estar distribuidos en varios computadores conectados en red.
2 ¿Qué es COM?
Esta pregunta puede responderse de cualquiera de las siguientes maneras:
2
IUnknown
IClassFactory
Class
Factory
Cliente
Objeto Registro
Envoltorio
Componente
La especificación de COM es un documento que puede obtenerse de
http://www.microsoft.com/com/. Este documento describe todos los aspectos que un
programador debe conocer para desarrollar aplicaciones COM.
Por otra parte, el sistema operativo debe proveer un número de facilidades para que las
aplicaciones COM puedan ejecutarse. En la actualidad solo algunas versiones de Windows
proveen este soporte en modo nativo.
Otra forma de describir COM es como una filosofía para el diseño y desarrollo de
aplicaciones. En la medida en que las aplicaciones se hacen mas grandes y complejas, el
desarrollo de programas monolíticos se vuelve impráctica. El desarrollo de aplicaciones se
facilita si éstas se modularizan dividiéndolas en componentes que pueden ser desarrollados de
manera independiente y que además pueden reutilizarse en el futuro.
Por último, COM es un estándar binario porque los componentes pueden ser utilizados
sin necesidad de tener acceso al código fuente: solo se requiere acceso al componente en forma
binaria. Esto permite que componentes elaborados por diversos proveedores puedan conectarse e
interactuar en forma significativa.
3 Interfaces COM
3
diferencia de los ambientes de programación convencionales, estos mecanismos son
independientes de las aplicaciones que usan los componentes y de los lenguajes de programación
usados para crear los objetos.
Un componente COM expone los servicios que ofrecen los objetos que contiene mediante
una o más interfaces. Estas interfaces están constituidas de colecciones de llamadas de función
especificándose, en cada caso, el tipo y la cantidad de parámetros esperados. La figura 2 ilustra
un componente COM. Algunos de los elementos mostrados en la figura se describirán en las
secciones siguientes.
Una vez que un componente COM ha sido creado, sus interfaces no pueden cambiarse.
Esto garantiza que todas las aplicaciones que usan este componente podrán seguir haciéndolo en
el futuro. Si se requiere modificar o incrementar la funcionalidad de un componente, se debe
agregar una nueva interface, preservando intactas las ya existentes.
2 Componente COM
{B45E9146-3349-4F77-9151-2BF646CB9CAF}
Para garantizar la unicidad de estos números se recomienda usar el programa guidgen.exe el cual
puede obtenerse de Microsoft. Todos los objetos COM deben implementar por lo menos una
interface IUnknown, cuyo GUID es:
{00000000-0000-0000-C000-000000000046}
así mismo, en cada componente COM, debe haber una Class Factory que implementa una
interface IClassFactory (además de su propio IUnknown) identificada por:
{00000001-0000-0000-C000-000000000046}
4 Tipos de componentes
Los componentes COM se pueden agrupar básicamente en tres categorías.
4
$ In-Process
$ Locales
$ Remotos
5 Infraestructura de COM
Para poder crear y usar COM se requiere que el sistema operativo provea la
infraestructura necesaria. En Windows esta reside en un DLL conocida como COM library, que
incluye lo siguiente:
Ademas de los servicios básicos mencionados hasta ahora, COM también construye una
infraestructura de otros tres componentes del sistema operativo:
$ Almacenamiento persistente.
$ Monikers.
$ Transferencias de datos uniforme.
Los monikers permiten asignar un nombre a una instancia específica de una clase (un
objeto específico) de forma tal que una aplicación puede reconectarse a exactamente ese objeto
5
con el mismo estado (en vez de un objeto cualquiera de esa clase).
import “unknown.idl”;
[ object, uuid(1000001-0000-0000-0000-000000000001) ]
interface ISum : IUnknown
{
HRESULT Sum ([in] int x, [in] int y, [out, retval] int* retval);
};
7 Funciones COM
$ CoInitialize(NULL)
$ CoCreateInstance(clsid, pUnkOuter, grfContext, iid, ppvObj) y
$ CoUninitialize()
CoIninialize inicializa al subsistema COM y debe ser invocada antes de cualquier otro servicio
COM. CoUninitialize, en cambio, debe invocarse al terminar la aplicación para cerrar la librería
COM, liberar los recursos y cerrar todas las conexiones RPC. La función CoCreateInstance se
utiliza para crear objetos de las clases deseadas. Los parámetros de esta última se describen a
continuación:
6
clsid REFCLSID UUID de la clase de la cual se desea el objeto
pUnkOuter IUnknown* El IUnknown del controlador, si existe. (Agregación)
grfContext DWORD Contexto (InProcess, local, etc.)
iid REFID Interface de inicialización deseada.
ppvObj void** Donde se retorna la interface deseada
Todas estas funciones retornan una condición de tipo HRESULT que indican si la
llamada tuvo éxito o si se produjo algún error.
8 La interface IUnknown
La interface IUnknown implementa los tres métodos indicados a continuación:
QueryInterface permite determinar si un objeto soporta la interface. iid, en cuyo caso retorna un
apuntador a la misma en ppv. AddRef y Release se usa para llevar la cuenta del número de
referencias a un objeto. Cuando el numero de referencias llega a cero, el objeto es destruido y se
libera la memoria que ocupaba. Estas funciones retornan una condición de tipo HRESULT para
permitir el manejo de errores.
10 La interface IClassFactory
Cuando un cliente llama la función CoCreateInstace, COM debe crear un objeto con la
interface deseada en la memoria del computador y devolver un apuntador con su ubicación. Para
lograr esto, debe determinar donde se encuentra el componente COM que contiene la
implementación de la interface deseada y como crear dicho objeto. La ubicación del objeto se
obtiene del registro, mientras que el mecanismo para crear el objeto debe obtenerse del
7
componente COM mismo; esto último se resuelve mediante IClassFactory. Los objetos
fabricadores implementan IClassFactory para crear otros objetos COM.
ambos métodos retornan una condición de tipo HRESULT. Los parámetros se describen en la
siguiente tabla:
11.1 El cliente
Abajo se muestra el programa cliente. Éste usa el componente COM cuya interface se
definió en la sección 6. Aunque este programa verifica las condiciones de error luego de cada
llamada, cuando ocurre un error sólo se muestra un mensaje y se permite que el programa
continúe su ejecución . Esto es una mala práctica y solo se justifica en este caso debido a que un
buen manejo de errores complicaría el el programa y dificultaría la comprensión de los conceptos
COM ilustrados.
// client.cpp
#include <iostream.h>
#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}};
8
void main()
{
cout << "Client: Calling CoInitialize()" << endl;
HRESULT hr = CoInitialize(NULL);
if(FAILED(hr))
cout << "CoInitialize failed" << endl;
IUnknown* pUnknown;
ISum* pSum;
cout << "Client: Calling QueryInterface() for ISum on " << pUnknown <<
endl;
hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum);
if(FAILED(hr))
cout << "IID_ISum not supported" << endl;
hr = pUnknown->Release();
cout << "Client: Calling pUnknown->Release() reference count = "
<< hr << endl;
int sum;
hr = pSum->Sum(2, 3, &sum);
if(SUCCEEDED(hr))
cout << "Client: Calling Sum(2, 3) = " << sum << endl;
hr = pSum->Release();
cout << "Client: Calling pSum->Release() reference count = " <<
hr << endl;
9
DllCanUnloadNow es utilizada por COM para determinar si la DLL puede descargarse de
memoria.
; component.def
LIBRARY component.dll
DESCRIPTION 'COM component example'
EXPORTS
DllGetClassObject @2 PRIVATE
DllCanUnloadNow @3 PRIVATE
11.3 El componente
// 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;
HANDLE g_hEvent; // For a later exercise with local components
// ISum
HRESULT __stdcall Sum(int x, int y, int* retval);
private:
ULONG m_cRef;
};
10
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;
}
11
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;
};
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;
}
12
CMySum *pMySum = new CMySum;
cout << "Component: CFactory::CreateInstance() " << pMySum << endl;
if(pMySum == NULL)
return E_OUTOFMEMORY;
if(clsid != CLSID_MySum)
return CLASS_E_CLASSNOTAVAILABLE;
Nótese que componet.cpp contiene dos clases. La clase CMySum que implementa las
clases IUnknown e ISum, mientras que la clase CFactory implementa Iunknown e IclassFactory.
13
11.4 Registro del componente
Antes de que el componente pueda ser utilizado, éste debe ser registrado a fin de que el
cliente pueda encontrarlo. Para esta operación puede emplearse un archivo de registro como el
siguiente:
REGEDIT4
[HKEY_CLASSES_ROOT\CLSID\{10000002-0000-0000-0000-000000000001}]
@="Inside DCOM Sample"
[HKEY_CLASSES_ROOT\CLSID\{10000002-0000-0000-0000-
000000000001}\InprocServer32]
@="C:\\Program Files\\DevStudio\\MyProjects\\Component\\Debug\\Component.dll"
12 ActiveX
El hecho de que las últimas dos definiciones son contradictorias (los controles OLE son
objetos COM que se comunican con su entorno mediante un conjunto de interfaces bien
definidas) hace pensar que probablemente la primera definición sea la mas correcta, sobre todo si
se toma en cuenta que la gente de mercadeo ha acogido ampliamente la idea (inicialmente
propuesta por Humpty Dumpty) de que las palabras significan cualquier cosa que se desee que
signifiquen.
14
Tomando la definición más amplia de AvtiveX, se puede representar la relación entre
COM, OLE y ActiveX como se muestra en la figura 3
$ Automatización,
$ Documentos ActiveX, y
$ Objetos (controles) ActiveX.
ActiveX
Documentos
Activación en sito
(Edición visual) Controles
Linking
Embedding
Drag-
Drag-and Drop
OLE
Macros
Transferencia de datos uniforme COM
Por último los controles ActiveX (antes controles OLE) definen un conjunto de interfaces
que deben ser implementadas para que un objeto pueda calificar como un ActiveX, así como las
interfaces necesarias para crear un contenedor de controles ActiveX. Los controles ActiveX se
15
implementan como componentes COM InProcess.
$ Inclusión y
$ Agregación
14 COM+
Para permitir que los componentes COM+ participen en servicios, se agregan dos
elementos adicionales a los componentes COM: un contexto y un conjunto de atributos. Esto
Agregador Contenedor
Objeto Objeto
4 Re-utilización en COM
16
permite determinar las características de ejecución del objeto: si es transaccional, si se va usar
balance de carga, si se va a usar una cola de componentes, etc. Cuando se invoca un objeto,
COM+ intercepta la llamada para examinar el contexto y ejecuta cualquier acción necesaria antes
de invocar al objeto. Al terminar el objeto su trabajo, el interceptor examina nuevamente el
contexto para determinar si se requiere alguna otra acción antes de retornar el control a la
aplicación. La figura 5 ilustra la estructura de un componente COM+ y su interacción con un
cliente.
En segundo lugar se esta tratando de imponer un modelo simple y escalable. Los clientes
crean objetos, los usan y los liberan inmediatamente. También se intenta que los clientes no
tengan mucho que hacer, que los servidores se hagan cargo del trabajo.
Por último, COM+ es una arquitectura simple y extensible. Los interceptores examinan el
contexto y hacen lo que sea necesario. Para agregar nuevos servicios solo debe ingresarse la
información necesaria al contexto.
$ Desarrollo de servidores
$ Servicios transaccionales
$ Seguridad
$ Administración
$ Colas de componentes (procesamiento diferido)
$ Manejo de eventos
$ Balance de carga
17
IUnknown
Contexto
Atributos
Cliente
Servidor
5 Componentes COM+
18
1 ............................................................................................................................... Introducción 1
12 ....................................................................................................................................ActiveX 14
14 ...................................................................................................................................... COM+ 16
19