4.2. CREACIÓN DEL CLIENTE
El cliente es
una aplicación informática o un ordenador que consume un
servicio remoto en otro ordenador conocido como servidor, normalmente a
través de una red de telecomunicaciones. También se puede
definir un cliente es cualquier cosa (que no sea un servidor) que se conecta a
un servidor.
En
los componentes COM no existe el concepto de herencia, para la reutilización se
utiliza:
COMPOSICION
o AGREGACIÓN.
COMPOSICIÓN
•En
la composición el objeto COM simplemente actúa a su vez como cliente del objeto
COM que contiene.
AGREGACIÓN
•Se
expone directamente la interfaz del objeto COM agregado, de modo que el cliente puede acceder de forma
transparente a las interfaces de los dos objetos COM.
COM+
es una ampliación al modelo de componentes COM para la construcción de aplicaciones empresariales, se encarga de proporcionar
una serie de servicios:
Seguridad
de grano fino, controla el acceso a cada método.
Esca labilidad, mediante balanceo de carga y
“object pooling”
Manejo de transacciones, a través de MTS(Microsoft
Transactional server).
Implementación
Se va
a construir un objeto COM capaz de almacenar la siguiente información sobre un
usuario:
Age -> short
Name -> LPSTR
Sex -> unsigned char
El
objetivo es poner de manifiesto cuales son las tareas básicas de las que es
responsable todo objeto COM.
EJ:
Tareas del COM
1.
Crear los GUID’s necesarios para el objeto y sus interfaces
2.
Definir las interfaces del objeto
3.
Implementar las funciones de la interfaz definida
4.
Registrar el servidor COM
EJ:
Crear los GUID’s
•El
API COM dispone del método CoCreateGuid que se encarga de esta tarea.
•Como
parte de la distribución de VS se puede encontrar el programa UUIUDGEN.exe para
realizar esta tarea, aunque internamente sencillamente llama al método del API
anterior. Generamos los 3 GUID’s que vamos a necesitar:
C:>uuidgen
-n3
acceeb00-86c7-11d0-94ab-0080c74c7e95
acceeb01-86c7-11d0-94ab-0080c74c7e95 acceeb02-86c7-11d0-94ab-0080c74c7e95
EJ:
Definir las Interfaces
•Definición
de la interfaz IUserInfo import "unknwn.idl" ;
[ object, uuid(acceeb02-86c7-11d0-94ab-0080c74c7e95)
] interface IUserInfo : IUnknown
{
[propget] HRESULT Age([out, retval] short *nRetAge);
[propput]HRESULT Age([in] short nAge);
[propget]HRESULT Name([out, retval] LPSTR
*lpszRetName);
[propput]HRESULT Name([in] LPSTR lpszName);
[propget]HRESULT Sex([out, retval] unsigned char
*byRetSex);
[propput]HRESULT Sex([in] unsigned char bySex);
}
EJ:
Definir las Interfaces
•Definición
de la type library y del objeto UserInfo
[uuid(acceeb00-86c7-11d0-94ab-0080c74c7e95),version(1.0)]
library UserInfo
{
[uuid(acceeb01-86c7-11d0-94ab-0080c74c7e95),]
coclass UserInfo
{
[default] interface IUserInfo;
}
}
•Las
interfaces en IDL creadas las compilamos a través de MIDL (incluido en VS) y se
obtienen los siguientes ficheros:
•Contenido
de UserInfo_i.c
const
IID IID_IUserInfo = {0xacceeb02,0x86c7,0x11d0,
{0x94,0xab,0x00,0x80,0xc7,0x4c,0x7e,0x95}};
const CLSID CLSID_UserInfo =
{0xacceeb01,0x86c7,0x11d0, {0x94,0xab,0x00,0x80,0xc7,0x4c,0x7e,0x95}};
const IID LIBID_UserInfo =
{0xacceeb00,0x86c7,0x11d0,
{0x94,0xab,0x00,0x80,0xc7,0x4c,0x7e,0x95}};
• Contenido de UserInfo_i.h
Este
fichero contiene las cabeceras del interfaz tanto en C como en C++
La
interfaz en C++ se declara como una clase abstracta con todos sus métodos
virtuales puros, de esta manera se fuerza a quien implemente la interfaz a
implementar todos sus métodos.
class IUserInfo {
public: virtual QueryInterface(REFIID iid, LPVOID
*ppv) = 0; .............}
class CUserInfo : IUserInfo { private: ULONG m_cRef;
private: short m_nAge; private: LPSTR m_lpszName; private: BYTE m_bySex;
public: STDMETHODIMP QueryInterface(REFIID iid, LPVOID
*ppv); public: STDMETHODIMP_(ULONG)AddRef(void); public:
STDMETHODIMP_(ULONG)Release(void); public: STDMETHODIMP get_Age(short
*nRetAge); public: STDMETHODIMP put_Age(short nAge); public: STDMETHODIMP
get_Name(LPSTR *lpszRetName); public: STDMETHODIMP put_Name(LPSTR lpszname);
public: STDMETHODIMP get_Sex(BYTE *byRetSex); public: STDMETHODIMP put_Sex(BYTE
bySex);
CUserInfo();
~CUserInfo();
};
•Implementación
del método QueryInterface
STDMETHODIMP CUserInfo::QueryInterface(REFIID iid,
LPVOID *ppv)
{
*ppv = NULL; if (IID_IUnknown == iid) *ppv =
(LPVOID)(IUnknown *)this; else if (IID_IUserInfo == iid) *ppv =
(LPVOID)(IUserInfo *)this; else
return E_NOINTERFACE; //Interface not supported
((IUnknown *)*ppv)->AddRef(); return NOERROR;
}
•Implementación del método AddRef
STDMETHODIMP_(ULONG) CUserInfo::AddRef(void)
{ return ++m_cRef;
}
•Implementación del método Release
STDMETHODIMP_(ULONG)CUserInfo::Release(void)
{ m_cRef-; if (0 == m_cRef)
{ delete this; g_cObjects-; if
(::ServerCanUnloadNow())
::UnloadServer(); return 0;
} return m_cRef;
}
Una
vez implementados los métodos de la interfaz Iunknow simplemente restaría implementar
el resto de métodos de la clase CUserInfo, los que corresponden a la interfaz
IUserInfo.
La
implementación de estos métodos es trivial, consiste únicamente en establecer y
devolver los valores de las propiedades definidas para contener el sexo, nombre
y edad del usuario.
EJ: Registrar el servidor COM
•La
información sobre el objeto COM debe estar en el registro de windows para que
los clientes puedan localizarlo, la especificación COM define que las dll’s que
contengan objetos COM deben implementar los siguientes métodos para esta tarea:
DllRegisterServer
– En esta función se escribirá la información necesaria en el registro para que
luego se pueda localizar el servidor COM.
DllUnregisterServer
– Esta función es la encargada de borrar la información sobre el COM escrita en
el registro.
EJ:
Registrar el servidor COM
•La
información que se debe almacenar en el registro sobre el servidor COM es la
siguiente:
HKEY_CLASSES_ROOT CLSID
{acceeb01-86c7-11d0-94ab0080c74c7e95} = Description
InprocServer32
C:\UserInfo\UserInfo.dll
•Los
programas como Regsrv32.exe que se utilizan para registrar objetos COM
simplemente cargan la dll y
invocan
el método DllRegisterServer
EJ:
Creación de un cliente
•El
cliente debe realizar las siguientes tareas:
Iniciar
la librería COM
Obtener
la interfaz
Manipular
el objeto a través de su interfaz
Liberar
las interfaces
Finalizar
la librería COM
EJ:
Iniciar la librería COM
•Para
iniciar la librería COM hay que llamar al método del API COM CoInitialize:
hr = CoInitialize(NULL); if ( SUCCEEDED(hr) )
{
...}
•El
método CoInitialize inicializa la librería en el thread de ejecución desde el
que se invoque. Es necesario llamar a CoInitialize desde cada thread de la
aplicación que quiera acceder a objetos COM.
EJ:
Obtener la interfaz
•Para
obtener la interfaz inicial llamamos al método CoCreateInstance, este creará
una nueva instancia de un objeto COM y nos devolverá un puntero a su interfaz.
IUnknown *pIUnknown = NULL; hr =
CoCreateInstance(CLSID_UserInfo, NULL,
CLSCTX_INPROC_SERVER, IID_IUnknown,
(LPVOID *)&pIUnknown);
if (SUCCEEDED(hr))
{....}
EJ:
Obtener la interfaz
•A
través del puntero a IUnknow obtener el puntero a la interfaz IUserInfo
hr = pIUnknown->QueryInterface (IID-IUserInfo,
(LPVOID *)&pIUserInfo); if (SUCCEEDED(hr))
{\\manipulación
del objeto}
EJ:
liberar las interfaces
•Para
liberar las interfaces hay que llamar al método Release, si el objeto COM no
tiene más interfaces referenciadas se borrara automaticamente:
pIUserInfo->Release();
pIUnknown->Release();
EJ:
Finalizar la librería COM
•La
librería COM se finaliza a través del método CoUninitialize, una vez llamado a
Este
método no se podrá seguir llamando a funciones de la librería COM ni
manipulando objetos COM.
REFERENCIAS:
Charte., F. (s.f.). Programación avanzada en Windows.
Anaya Multimedia (ISBN 84-415-0832-1 ).
ITESCAM. (s.f.). https://www.itescam.edu.mx. Obtenido
de https://www.itescam.edu.mx:
https://www.itescam.edu.mx/principal/sylabus/fpdb/recursos/r109506.PDF