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