UNIVERSIDAD AUTONOMA METROPOLITANA UNIDAD: lztapalapa ’ DIVISION: Ciencias Basicas e Ingeniería ’ CARRERA: Licenciatura en Computación MATERIA: Proyecto Terminal I y II ’ ’’ TITULO: Interfaces de Programación de Aplicaciones utilizando COM FECHA: 12 de Julio de 1999 - ./ALUMNOS: ASESOR: e u Cortes Torres Isabel Cristina 94219468 Juárez Olivo Adriana Berenice 94217242 López Ponce Ramiro Antonio 93220496 d a n d o Castro Careaga Departamento de Comoutación Interfaces de Programación de Aplicaciones utilizando COM COM desde Visual Basic Adriana Juárez Olivo Isabel Cortes Torres Ramiro López Ponce División de Ciencias Básicas e Ingeniería Universidad Autónoma Metropolitana Unidad lztapalapa Asesor de Proyecto Ing. Luis Fernando Castro Careaga Departamento de Computación Universidad Autónoma Metropolitana Unidad lztapalapa Interfaces de Programación de Aplicaciones utilizando COM COM desde Visual Basic Adriana Juárez Olivo Isabel Cortes Torres Ramiro López Ponce El contenido de ésta obra corresponde a la documentación del proyecto de la Licenciatura en Computació I y II llevado a término por los autores, de acuerdo con el plan de estudios vigente de la Universidad Autónoma Metropolitana Impreso en México Esta obra se terminó de imprimir en Julio de 1999 en las instalaciones del Edificio T de Ciencias Básicas e Ingeniería de la Universidad Autónoma Metropolitana Unidad lztapalapa Av. Michoacán y la Purísima Col. Vicentina Delegación lztapalapa 09340 México, D.F. Se imprimieron 2 ejemplares Agradecimientos y Dedicatorias Existieron muchas personas, las cuales contribuyeron a mi formación profesional. Principalmente quiero dar las gracias a mi padre por su incondicional apoyo y amor, sobre todo por la gran fe que siempre ha tenido en mi; a mi madre por sus consejos y sugerencias y a mi tía por brindarme la ayuda y serenidad que en sus momentos necesite. Ellos fueron quienes hicieron esto posible: Juan Manuel Juárez Valencia. mi padre Luz María Olivo González, mi madre María Teresa Olivo González, mi tía Especialmente a una persona que compartió conmigo una de las fases más importantes de mi vida y que gracias a su ayuda y motivación logre concluir mis estudios profesionales: Alvaro Israel Ruiz Rivera, mi novio, amigo y compañero. También quiero agradecer a Dios, por permitirme llegar hasta donde hoy estoy. Gracias a todos y a ustedes dedico este triunfo. Adriana Berenice Juárez Olivo Agradecimientosy Dedicatorias on muchas las personas que contribuyeron con su tiempo y esfuerzo a mi formación profesional. En particular quiero dar gracias a mi Madre por su incondicional apoyo y su admirable generosidad y comprensión. A todos mis hermanos que sin su tolerancia, paciencia y ayuda esta tarea hubiera sido mucho más difícil y sobretodo por todos aquellos consejos y sugerencias que me dieron en su momento. Quiero agradecer a mis amigos por compartir momentos de fracaso, adversidad y de éxito durante la carrera. También estoy en deuda con mis profesores por su guía, por su disposición de compartir sus conocimientos y los beneficios de su experiencia, en especial de mi Asesor, por su incomparable altruismo y comentarios que no son más que un aliciente para continuar con mi superación tanto profesional como personalmente. S inalmente estoy profundamente agradecida con Dios por haberme permitido llegar hasta donde estoy. Gracias a El soy lo que soy. F C on admiración, respeto y cariño, a todos ellos, les dedico este esfuerzo. Espero nunca defraudar la confianza que han depositado en mí. Isabel Cristina Cortés Torres. Agradecimientos y Dedicatorias A Dios, por permitirme estar aquí A mi Mamá por su gran voluntad y amor A mis Hermanos por que juntos caminamos A Claudia por su amor incondicional A mi Familia por el gran apoyo recibido A mis Amigos por el tiempo vivido A las sonrisas de Priscila, Neftali y Gabriel Ramiro López Ponce lndice INTRODUCCION 1 Capitulo I MODELO CLlENTElSERVlDOR 4 1. I Cliente 4 I. I. 1 Características 4 I .I.2 Sistemas Operativos 4 1. I .3 Acceso a las Bases de Datos 5 1.2 Servidor 1.2.1 Características 6 6 1.2. I. 1 Multiprocesamiento 6 1.2.I.2 Multihilos 7 1.2.1.3 Arreglos de discos 7 1.2.2 Clasificación de Servidores 8 1.2.2.1 Servidor de archivos 8 1.2.2.2 Servidor de aplicaciones 8 1.2.2.3 Servidor de bases de datos 8 1.3. Definición de Cliente/Servidor 9 1.4. Características generales de Cliente/Servidor 10 1.4.1 Mantenibilidad 10 1.4.2 Modularidad 10 1.4.3 Adaptabilidad 10 1.4.4 Escalabilidad 11 1.4.5 Portabilidad 11 1.4.6 Estándares/Sistemas abiertos 12 1.4.7 Autonomía 11 1.4.8 Flexibilidad 11 1.5.Comunicación Cliente/Servidor 12 1.5.1 Modelo Conversacional 12 1.5.2 Modelo de Mensajes 13 1.5.3 RPC's 13 1.6. Costos y Beneficios de Cliente/Servidor 14 1.7 Beneficios de la Arquitectura Ciiente/Servidor 15 1.8 Desventajas de la Arquitectura Cliente/Servidor 15 CAPITULO II CONCEPTOS GENERALES COM Y DCOM 17 2.1 Introducción 17 2.2 Creando aplicaciones dimensionables con Windows NT y DCOM 17 2.3 Neutralidad de los Lenguajes de Programación 19 2.4 Gestión de la conexión 19 2.5 Interfaces múltiples 19 2.6 independencia en la ubicación y equilibrio de carga 20 2.7 Seguridad frente a los fallos y tolerancia a los errores 20 2.8 Integración de base de datos 21 2.9 Resumen 22 Capitulo 111 COMUNICACIÓN CLIENTE SERVIDOR BAJO EL CONCEPTO DE COM 3.1 Antecedentes 23 23 3.2 Objetos 23 3.3 Interfaces 23 3.4 ldentificadores en COM 27 3.5 interface estándar 27 3.6 Interfaces Personalizados 29 3.7 El compilador MlDL 30 Capitulo IV CREACIÓN DE UN OBJETO COM Y USO DE SUS INTERFACES 4.1 Antecedentes 32 32 4.2 GUiD's y Registro 33 4.3 Módulos componentes de clases e interfaces 34 lndice 4.4 Obteniendo otra interface con Querylnterface 34 4.5 Controlando el ciclo de vida del objeto 35 4.6 Interfaces que permiten interoperabilidad 36 4.7 Clase objeto 37 4.8 lmplementado la clase objetos 38 4.9 lmplementando los métodos de la clase objeto 39 Capitulo V IMPLEMENTACIÓN DEL OBJETO 42 5.1 lmplementando el propio objeto 42 5.2 El diseño de CmyObject 42 5.3 lmplementando interfaces multiples usando herencia multiple 43 5.4 lmplementando a Querylnterface 47 5.5 lmplementando a AddRef y Release 47 5.6 El constructor y destructor 48 5.7 lmplementando una interface propia 50 5.8 Contruyendolo 51 5.9 El objeto clase y la fabrica de clases 53 5.9.1 El objeto clase 53 5.9.2 Porque existe un objeto clase 54 5.9.3 Otra forma de crear objetos y cuando usarla 55 5.9.4 lmplementando el objeto clase 55 5.9.5 Como es creado este objeto clase 56 5.9.6 Como CoGetClassObject obtiene el objeto clase 56 5.9.7 lmplementando los métodos del objeto clase 57 5.9.7.1 1Unknown::AddRef y 1Unknown::Release 57 5.9.7.2 lUnknown::Querylnterface 58 5.9.7.3 1ClassFactory::Createlnstance 59 5.9.7.4 1ClaccFactory::LockServer 60 5.9.7.5 DllCanUnloadNow 60 5.9.8 Usando el objeto desde Visual Basic 60 lndice 5.9.9Usando el objeto desde Visual J++ Capitulo VI AMBIENTE CLIENTEiSERVIDOR BAJO COM 63 65 6.1Antecedentes 65 6.2Clientes y Servidores COM 65 6.3La Librería COM y el Manejo de Control de Servicio 66 6.4Arquitectura para objetos distribuidos 66 6.5Objetos Conectables y Eventos 67 6.6Transferencia de Datos Uniforme 70 6.7Formatos de datos y medios de transferencia 71 6.8Responsabilidades de una aplicación COM 72 Capitulo VII APLICACI~N 73 7.1Objetivo 73 7.2Descripción 73 7.3Descripción del Diseño 73 7.3.1Base de Datos 73 7.3.2Cliente 74 7.3.3Servidor 78 7.4 Implementación 82 7.4.1Creación de la aplicación Cliente 82 7.4.2Creación de la aplicación Servidor 7.4.3Generación de Setup para la aplicación 88 Cliente-Servidor Remote Automation Ó COM 7.4.3.1Creación del setup para el Servidor 90 7.4.3.2 Creación del setup para el Cliente 92 90 CONCLUSIONES 95 BlBLlOGRAFlA 98 Introducción Dos décadas atrás, el procesamiento de datos se basaba en el uso de poderosos mainframes, el acceso a éstos se llevaba a cabo por medio de rudimentarias terminales que sólo permitían la comunicación con el procesador central. Los métodos para el procesamiento de la información resultaban ser arduos y complejos debido a la centralización de los recursos y a las hostiles interfaces de usuarios. Así que cuando aparecieron las primeras computadoras personales, cerca de los años ochenta, su crecimiento fue inmediato debido a su facilidad al acceso de los datos, así como por sus interfaces amigables. Sin embargo, las PC siguieron siendo incapaces de manejar el procesamiento de datos necesarios para las grandes empresas. Las redes de área local (LAN, Local Area Network) dieron una solución a este problema interconectando PC y mainframe. Esto es, las PC son utilizadas como terminales inteligentes (amigables), las cuales facilitan la conexión del usuario con el procesador central (MAINFRAME). Actualmente, tanto las PC como las redes de área local son usadas en casi la totalidad de las empresas; las PC permiten contar con una variedad de procesadores de texto, hojas de cálculo y software de basa de datos, mientras que el uso de redes de área local permite compartir archivos y periféricos (impresoras, modems, unidades de respaldo, etc.). Sin embargo, la mayoría de las aplicaciones de “misión crítica” pertenecen en “manos” de los mainframes (y computadoras). El objetivo de la industria de redes y en particular la industria de los servidores de base de datos se centra en “bajar” las aplicaciones existentes en los mainframes hacia servidores PC y LAN, usando para ello la arquitectura cliente/servidor. Esto tiene como consecuencia el desarrollo de nuevos sistemas operativos enfocados hacia redes de computadoras y desarrollo de manejadores de base de datos capaces de soportar el esquema cliente/servidor. El término cliente/servidor se utiliza frecuentemente como sinónimo del procesamiento cooperativo o distribuido. Pero el procesamiento distribuido no es nuevo, desde los años 70 existen sistemas de computo que pueden considerarse distribuidos, pero se desarrollaban de tal manera que la distribución de las funciones y los datos quedaba implícita en el diseño y código del programa, como también en las comunicaciones entre las aplicaciones. Esto dio como resultado aplicaciones distribuidas de forma cooperativa con una estructura muy rígida. Los programas y datos se encontraban asociados unívocamente, por lo que los datos no se accesaban de una manera global desde las diferentes aplicaciones, sino como parte integral de éstas mismas. Actualmente, las computadoras personales y los paquetes de software de aplicaciones proliferan comercialmente. Las estaciones de trabajo están conectadas a redes de área local (LAN) mediante las cuales se comparten aplicaciones y datos. Las nuevas tecnologías de distribución de funciones y datos en una red permiten desarrollar aplicaciones distribuidas de una manera trasparente, de forma que múltiples 1 Introducción procesadores puedan ejecutar partes distintas de una aplicación. Si se elige una adecuada infraestructura de sistemas distribuidos y herramientas de desarrollo, las aplicaciones resultantes podrán transladarse a plataformas de diferentes proveedores. El proceso distribuido se reconoce actualmente como el nuevo paradigma de los sistemas de información. Este cambio ha surgido fundamentalmente como consecuencia de importantes factores (negocio, tecnología, proveedores), y se apoya en la existencia de una gran variedad de aplicaciones estándares y herramientas de desarrollo fáciles de usar que soportan un entorno informático distribuido. Esta infraestructura no debe ser implementada sólo por razones tecnológicas o de moda, deberá utilizarse para desarrollar o rediseñar aplicaciones que soporten los objetivos de la empresa. Sin embargo, la migración de aplicaciones ya existentes sin modificar su funcionalidad, puede acarrear costos substanciales y no producir los resultados deseados. Las condiciones que sugieren la implantación del ambiente cliente/servidor en una empresa son: 0 0 0 0 Cambios estructurales y organizativos. Cambios en los organigramas con mayor delegación en personas y departamentos. Respuesta a la dinámica del mercado. Cambios en los procesos de negocio. El mundo en constante cambio Procesos de negocios flexibles Organización flexible Ambiente de cómputo flexible ‘0s +2=- Permite a% empresa obtener una ventaja sobre sus competidores en un mercado con cambios constantes 2 Introducción Las razones que impulsan el crecimiento de las aplicaciones cliente/servidor son: 0 0 0 0 La demanda de sistemas más fáciles de usar, que contribuyan a una mayor productividad y calidad. La relación precio/rendimiento de las estaciones de trabajo y de los servidores. La creciente necesidad de acceso a la información para la toma de decisiones y el soporte de los procesos mediante aplicaciones más ajustadas a la estructura organizativa de la empresa. La utilización de nuevas tecnologías y herramientas de alta productividad más aptas para la dinámica del mercado. Enfocado correctamente, el modelo cliente/servidor permite ejecutar las aplicaciones en la plataforma informática más adecuada para maximizar el beneficio operativo. También significa la posibilidad de reubicar funciones y datos, es decir, modificar los procesos de negocios sin alterar la lógica de la aplicación. La selección de herramientas adecuadas conduce a un desarrollo acelerado de las aplicaciones y mediante la reutilización de servidores puede reducirse notablemente la tarea de mantenimiento. 3 Cap. 1. Modelo Cliente /Servidor En este Capitulo se explicarán los conceptos Cliente y Servidor, mencionando las principales características de cada uno de ellos para describir finalmente el Modelo Cliente/Servidor, presentando sus ventajas y desventajas. 1.1 Cliente AI software para cliente se le llama “Front-end” puede estar en los más diversos ambientes como UNIX, MSDOS, WINDOWS, MACs, etc., permite al usuario final interactuar con la computadora y contiene al menos alguna aplicación lógica. La mayoría del software cliente proporciona la característica popular de una interface de usuario gráfica (GUI) lográndose un uso amigable. 1.I.ICaracterísticas En la arquitectura ClienteíServidor un cliente es un proceso que interactúa con el usuario y cuenta con las siguientes características: 0 Un Front-end puede encontrarse en una amplia gama de software. Puede ser tan sencillo como una herramienta existente de usuario final como una hoja de calculo o tan complejo como un programa en C o C++. 0 Presenta una interfaz al usuario (U1 User Interface), la cual tiene como objetivo enviar y recibir información del Servidor. Debido a que una arquitectura Cliente/Servidor puede consistir de múltiples clientes, es posible que múltiples interfaces puedan correr simultáneamente, cada cliente cuenta con su propia interfaz. 0 Crea uno o más queries en un lenguaje predeterminado para ser enviados al Servidor. El Cliente y el Servidor pueden comunicarse a través de un lenguaje estándar. 0 Se comunica hacia el Servidor a través de un proceso de comunicación. Idealmente este proceso es transparente al usuario. 0 Los Front-ends continúan incorporando características orientadas a objetos. 1.I.2 Sistemas Operativos El primer propósito de un sistema operativo es proporcionar a las aplicaciones los recursos de hardware de los equipos de cómputo como memoria, almacenamiento de disco, etc., y manejo con los dispositivos externos como impresora, scanner, etc. La transportabilidad de nuestras aplicaciones en un Front-end depende primordialmente de los sistemas operativos en los que sea capaz de trabajar. 4 Cap. 1. Modelo Cliente /Servidor Actualmente nos encontramos en el mercado con una gran gama de sistemas operativos y en gran medida las empresas cuentan con diversos equipos, teniendo como consecuencia, también una gran diversidad de sistemas operativos. En las empresas con la diversidad de plataformas, antes mencionadas, no les conviene “casarse” con un único sistema operativo y mucho menos propietario, por io que se recomienda desarrollar las aplicaciones Cliente en un Front-end que trabaje sobre una gran variedad de sistemas operativos, esta característica nos ahorrara tiempo de trabajo ya que al exportar nuestra aplicación de un sistema operativo a otro serán mínimas las modificaciones o quizás nulas. Entrando en detalles con los sistemas operativos debemos de tener en cuenta cuantas diferentes configuraciones de hardware pueden soportar dichos sistemas operativos. Dando algunos ejemplos, el MS-DOS sólo puede correr en PC‘s, Windows también fue hecho para trabajar en PC‘s, a diferencia de UNiX que puede trabajar en la gran mayoría de computadoras ya sea PC’s, WorkStations, Minis, etc. dándole la característica de portabilidad. También hay que tomar en cuenta que el sistema operativo donde corra nuestra aplicación incluya interfaces de usuario gráficas como Windows, OS/DOS Warp, Solarys, etc., con el fin de facilitar el manejo de la aplicación al usuario final [DAW93]. 1.1.3 Acceso a las Bases de Datos Uno de los usos más populares de los sistemas Cliente/Servidor es el de permitir a los usuarios finales el acceso a los datos de un gran almacén como el de una base de datos. Muchas herramientas query ayudan a llevar a cabo este propósito. El desarrollo de las herramientas query en primera instancia se pensaba que iban en contra de la producción de bases de datos mainframe, sin embargo actualmente es frecuente que se les instale un manejador de base de datos relaciona1 (RDBMS) donde se le pueda accesar fácilmente por medio de SQL o herramientas generadoras de SQL [COD90]. Además de los RDBMS también existen varias bases de datos desarrollados para trabajar sobre PC’s,las cuales no suelen ser sistemas relacionales, pero por lo general permiten a los usuarios expresar un requerimiento en términos de SQL y posteriormente el software convierte el requerimiento en el formato que la base de datos pueda entender. 5 Cap. 1. Modelo Cliente /Servidor 1.2 Servidor En la arquitectura Cliente/Servidor, el Servidor “back-end” maneja los recursos de información, es decir, almacena, recupera y protege los datos. El Servidor revisa los datos requeridos y si es necesario, genera y manda los datos solicitados a un Cliente u otro Servidor. 1.2.1 Características Un Servidor es un proceso o un conjunto de procesos, que debe existir en una máquina y su objetivo será el de proveer un servicio a uno a más clientes, posee las siguientes características: 0 Un Servidor da un servicio a los clientes. Un servicio otorgado por un Servidor puede requerir de un apoyo mínimo por parte de éste o bien de un cálculo intenso como podrían ser Servidores de base de datos o Servidores de procesamiento de imágenes. 0 Un Servidor ideal esconde su estructura al Cliente y al usuario, es decir, se establece una comunicación transparente entre el usuario y el Servidor, sin importar la plataforma del Servidor (hardware y software), así como también de la tecnología de comunicación que se utilice. 0 Cuando se elige una máquina como Servidor debe de contemplarse algunas características técnicas como el multiprocesamiento, multihilos y arreglos de discos. Hay que tomar en cuenta que la mayoría de las veces, si no es que siempre, los Servidores juegan un papel crítico, donde una falla podría ser catastrófica para cualquier tipo de empresa, es por eso que además deben de contemplar redundancia de algunos componentes tales como manejadores de discos, fuente de energía, discos espejo, etc. 1.2.1.I Multiprocesamiento Los fabricantes están incluyendo múltiples procesadores en su hardware para incrementar la velocidad de procesamiento. Varios procesadores nos permiten realizar el multiprocesamiento simétrico o funcional. Con el multiprocesamiento simétrico se puede asignar dinámicamente una tarea a un procesador. Los recursos de procesamiento son maximizados. Cuando hay una tarea por realizar un procesador desocupado la lleva a cabo. El multiprocesamiento funcional permanentemente asigna un conjunto de tareas a un procesador. Consecuentemente, un procesador puede “flojear” cuando otro puede estar sobrecargado de trabajo. 6 Cap. 1. Modelo Cliente /Servidor 1.2.1.2 Multihilos Un hilo es la unidad más pequeña de ejecución que el sistema puede listar. Cada apuntador, una prioridad, el estado del CPU y una hilo consiste de una pila, un entrada en la lista de espera del sistema. Un hilo puede ser bloqueado, agregado para ejecución o ejecutado. Los hilos se comunican a través de mensajes y compiten por adueñarse de varios semáforos los cuales controlan la asignación de recursos de cómputo. Los sistemas operativos antiguos llevaban a cabo la multitarea para crear múltiples procesos, pero esto desarrollaba overhead, sin embargo con el ambiente de multihilos, un proceso es dividido en tareas independientes ejecutables. Estos hilos colectivamente realizan el trabajo permitiendo a las aplicaciones realizar muchas tareas simultáneamente [DAW93]. 1.2.1.3Arreglos de discos Los arreglos de discos son de gran utilidad para el usuario, debido a que pueden recuperarse de alguna falla reemplazando el manejador de disco dañado estando el Servidor en línea. En un ambiente multiservidor, los Servidores que atienden a un determinado número de clientes se comunican entre sí transparentemente, sin que el Cliente se de cuenta de esto, por lo que, en un ambiente de procesamiento distribuido, el Cliente no podrá ser capaz de localizar al Servidor o Servidores que los atienden. De este modo, una arquitectura Cliente/Servidor divide una aplicación en procesos independientes, los cuales son procesados en máquinas separadas que se encuentran conectadas a través de una red. Entre más avanzado sea el sistema operativo de red más se reducirán, en código, el tamaño de los procesos por ejecutar. Por ejemplo, Microsoft LAN Manager da una amplia gama de funciones para la implementación de un sistema Cliente/Servidor, es decir, el sistema corre soportado por las funciones dadas por Microsoft LAN Manager, lo cual reduce el tiempo de desarrollo. Si el mismo sistema se implementara en un sistema operativo de red que únicamente provee de las posibilidades de compartir archivos y periféricos, el código de las aplicaciones sería fácilmente el triple. Los Servidores pueden ser computadoras de propósito general, especializadas (para hacer eficientes ciertas tareas), o bien, computadoras con la capacidad de multitasking. Cualquier actividad que puede ser catalogada de uso general o reutilizable (comunicaciones, cálculos numéricos intensos, mail/fax, etc.) es un candidato para ser Servidor. 7 Cap. 1. Modelo Cliente /Servidor 1.2.2 Clasificación de Servidores El Servidor fue desarrollado para compartir periféricos costosos como impresoras láser, lectores de CD ROM, etc. Además de los periféricos, también se desarrollo para compartir los datos y en cuanto a esto se pueden clasificar los Servidores como[BOC94]: 1.2.2.1 Servidor de archivos Los Servidores de archivos están muy orientados a I/O (entradas y salidas). Estos Servidores colocan gran cantidad de información en sus sistemas de almacenamiento y pasan los datos sobre una red. Cuando los datos de un archivo son solicitados, el Servidor transmite todos los registros al Cliente, saturando de esta forma las redes. Debido a que el Servidor manda todo el archivo del cual se requiera alguna información y no solamente los registros especificados, éste debe tener gran capacidad y un muy rápido acceso al disco duro. 1.2.2.2 Servidor de aplicaciones Este tipo de Servidor se caracteriza por prestar servicios similares a los que presta un mainframe. Cuando las aplicaciones de un mainframe son cambiadas a otra plataforma tratando de reducir los costos, una de las opciones consiste en instalas las aplicaciones sobre una máquina menos grande que corra el mismo software. 1.2.2.3 Servidor de bases de datos Este es el uso más típico de Servidor. Las aplicaciones corren sobre los clientes. El Servidor de base de datos acepta requerimientos y pasa el resultado al Cliente. La función de manejo de datos es del Servidor y el Cliente se encarga de ejecutar una aplicación específica. El Servidor de base de datos mejora el manejo de requerimientos y solo envía al Cliente los datos que satisfacen el requerimiento. Esto es más eficiente en términos de la carga de la red que una arquitectura file-server. Mediante herramientas SQL se pueden procesar los registros en conjunto, una aplicación con una sencilla instrucción de SQL puede recuperar o modificar un conjunto de registros del Servidor. 8 Cap. 1. Modelo Cliente /Servidor 1.3. Definición de ClientelSewidor Como primer paso se requiere conocer el término Cliente/Servidor, el cual nos ayudará a comprender su significado, cada autor contempla su propio concepto sin embargo todos tienden a coincidir. A continuación se listan algunas definiciones: La arquitectura Cliente/Servidor es una arquitectura de procesamiento en la cual una aplicación es patticionada a través de múltiples procesadores, los cuales cooperan de una manera unificada para completar un proceso como una tarea. La computación Cliente/Servidor es un modelo de cómputo en el cual una aplicación es particionada entre múltiples procesadores (front-end y el back-end), los procesadores cooperan (transparente al usuario) entre sí para completar el procesamiento como una sola tarea unificada. Los productos para este ambiente permiten administrar a los procesadores para que juntos realicen una misma tarea dando la ilusión de un solo sistema. Los recursos compartidos se encuentran colocados como Servidores, los cuales ofrecen uno o más servicios. Las aplicaciones son colocadas como clientes, los cuales accesan los servicios autorizados. La arquitectura es recursiva, esto es, que un Servidor puede transformarse en Cliente y realizar peticiones de servicio hacia otro Servidor en la red. “Cliente/Servidores un diseño de aplicación enfocada en la descomposición de un sistema de información dentro de un número pequeño de funciones del Servidor, ejecutándose sobre una o más plataformas, que proporcionan servicios de uso común a un número grande de funciones Cliente, que están interconectadas y realizan trabajos definidos sobre los servicios comunes proporcionados por las funciones Servidor” [vAU94]. “En la computación Cliente/Servidor uno o más clientes y uno o más Servidores bajo un sistema operativo y sistemas de comunicación permiten, un sistema de cómputo distribuido. A este compuesto se le suele llamar sistema Cliente/Servidor”[SIN92]. “Básicamente, una arquitectura Cliente/Servidor es un enfoque computacional que separa procesos sobre plataformas separadas interactuando una con otra que permite compartir recursos tomando la mejor ventaja de los diferentes dispositivos”[BOC94]. Resumiendo Cliente/Servidor es un modelo de cómputo, para crear sistemas de información usando diferentes tipos de tecnologías, que permiten la distribución de los recursos dividiendo las tareas de la aplicación. 9 Cap. 1. Modelo Cliente /Servidor CLIENTE 1 ,/q SERVIDOR I ‘7 CLIENTE n ... CLIENTE 2 CLIENTE 3 1.4. Características generales de ClientelServidor A continuación se enlistan las características que hacen a la arquitectura Cliente/Servidor más poderosa que otras. 1.4.1 Mantenibilidad La descomposición de sistemas monolíticos y rígidos en módulos independientes facilitan el mantenimiento de las aplicaciones. 1.4.2 Modularidad La arquitectura Cliente/Servidor es construida por medio de módulos conectables entre sí. Cada Cliente y Servidor es un módulo, el cual es independiente y puede ser reemplazado. Nuevas funciones pueden ser agregadas escalando los módulos existentes, o bien, creando nuevos módulos. 1.4.3 Adaptabilidad La arquitectura Cliente/Servidor puede distribuir de diferentes formas la lógica de presentación, procesamiento (lógica del negocio) y datos entre el Cliente y Servidor. 10 Cap. 1. Modelo Cliente /Servidor La adaptabilidad se refuerza con la capacidad de recursión de la arquitectura Cliente/Servidor (un Servidor puede convertirse en un Cliente y realizar peticiones). La recursión permite crear servicios lógicos en donde un proceso es ejecutado por más de un Servidor, y el acceso a los servicios físicos es realizado de una forma indirecta, lo que oculta a los usuarios la estructura de la arquitectura, la cual puede ser reconfigurada sin afectar la imagen que el usuario tiene del sistema. I Peticiones Servicios Servicio físico Servicio físico 1.4.4 Escalabilidad Junto con las capacidades de modularidad, uso de estándares y adaptabilidad, la arquitectura Cliente/Servidor puede ser escalada para abarcar los cambios en las necesidades del negocio. I.4.5 Portabilidad El poder de procesamiento puede encontrarse en diferentes plataformas, desde computadoras portátiles hasta poderosos mainframes. Construir un ambiente Cliente/Servidor basado en estándares permite colocar los componentes de una aplicación en la plataforma de cómputo en donde se obtenga su mayor rendimiento. 11 Cap. 1. Modelo Cliente /Servidor 1.4.6 Estándares/Sistemasabiertos El uso de estándares crea ambientes heterogéneos en donde existen distintos protocolos de red, distintas plataformas de hardware, diversas configuraciones de redes y sistemas operativos. 1.4.7 Autonomía Los clientes pueden poseer mínimas configuraciones de cómputo como podrían ser: computadoras sin disco duro o terminales gráficas, o bien, totalmente configuradas para realizar algún tipo de procesamiento. Con una adecuada configuración, cada Cliente y Servidor puede trabajar en forma independiente. 1.4.8 Flexibilidad La arquitectura Cliente/Servidor permite modelar las relaciones más complejas entre usuarios y equipo de cómputo. La arquitectura Cliente/Servidor puede reducir el costo de mantenimiento debido a que las aplicaciones heredan los atributos de la arquitectura sobre la cual está construida. Por lo que las aplicaciones construidas sobre un ambiente Cliente/Servidor son: escalables, portables, adaptables, modulares, etc. Estas capacidades facilitan el mantenimiento de las aplicaciones. También se puede incrementar la productividad del software, eliminando o minimizando la necesidad del desarrollo de nuevo; esto es debido a la existencia de librerías compartidas, por lo que al aumentar el número de librerías el tiempo de construcción de nuevas aplicaciones decrece. La arquitectura Cliente/Servidor establece una división Óptima de trabajo entre las aplicaciones Cliente y los Servidores de bases de datos. Las aplicaciones Cliente interactuan y presentan información a los usuarios. Los Servidores de bases de datos llevan a cabo la manipulación de los datos a una gran velocidad, protegen la integridad de los datos. Da el control de los datos bajo ambientes distribuidos al administrador del Servidor de bases de datos y al usuario final la flexibilidad para el uso de archivos o herramientas de su elección. 1.5. Comunicación Ciiente/Servidor Diferentes tipos de comunicación son usados por los sistemas Cliente/Servidor, los tres más importantes son: Conversacional, Llamada de Procedimientos Remotos (RPC) y mensajes. SQL es de alto nivel y es usualmente construido sobre uno de los tres anteriores (frecuentemente sobre RPC) [BOC94]. IS.1 Modelo Conversacional Un ejemplo del modelo conversacional se encuentra en el APPC de IBM. En SNA, el término “conversation” se refiere a la comunicación entre procesos durante una sesión. 12 Cap. 1. Modelo Cliente /Servidor El modelo conversacional es particularmente apropiado para situaciones que involucran muchas interacciones por transacción entre dos puntos, proporciona un control estricto para interacciones detalladas. Proporciona e implementa rutinas que permite ejecuciones traslapadas (overlap). 1.5.2 Modelo de Mensajes Algunos productos que usan este modelo son Windows de Microsoft, Presentation Manager y CICS. Con Windows y Presentation Manager los mensajes son usados entre las interfaces de usuario y procesos Windows. El concepto de mensajes es familiar para cualquiera que entienda los fundamentos de mensajes electrónicos (e-mail). Usando mensajes, sí un Cliente requiere datos de un Servidor de base de datos, el Cliente formatea el requerimiento en un mensaje y a su vez el Servidor proporciona la respuesta en forma de un mensaje también. Como lleguen los mensajes, son colocados en una cola; en cuanto se este listo para procesar un mensaje, este es borrado de la cola. Cuando los mensajes entran a la cola pueden ser ordenados de una de las tres formas siguientes: FIFO (primero que entra primero que sale), LIFO (Último que entra primero que sale) o de acuerdo a la prioridad asignada al mensaje. Un Cliente puede mandar un mensaje a cualquier número de Servidores. Los manejadores de colas son necesarios en ambos, tanto el Cliente como el Servidor. Los mensajes han sido desarrollados por sistemas de procesamiento de transacciones en línea como IMS y CICS. 1.5.3 RPC's Con RPC's, el procedimiento o subrutina se localiza sobre otra máquina en la red. Un RPC permite a un programa o un proceso sobre una computadora ejecutar un proceso sobre un sistema deferente que se encuentra en otra computadora remota. Los parámetros que sean necesarios son pasados cuando se llama al procedimiento. El procedimiento remoto tiene código que entiende que hacer con la llegada de mensajes, como responder a estos y como obtener los resultados requeridos para la llamada del procedimiento. Hay una gran variedad de diferentes implementaciones de RPC's. las herramientas generalmente proporcionan un lenguaje y un compilador que facilita la creación de código fuente portable así como un Run-Time. El desarrollador de aplicación usa el lenguaje proporcionado por la herramienta RPC para crear una especificación describiendo aspectos de funcionalidad mientras el Run-Time manipula el ambiente mandando y recibiendo datos a través de la red. 13 Cap. 1. Modelo Cliente /Servidor 1.6. Costos y Beneficios de ClientelServidor Los costos de la implementación de soluciones Cliente/Servidor no deben contemplarse sólo en términos absolutos, sino que deben medirse en función del beneficio que reporten los nuevos desarrollos. Como el precio de las computadoras personales se han reducido en los Últimos años, con frecuencia se comete el error de pensar que las soluciones Cliente/Servidor son económicas, o más económicas que las basadas en mainframes o minicomputadoras.Algunos estudios muestran que el costo del hardware y software en un periodo de cinco años representa solamente el 20% de los costos totales y el 80% restante son costos de infraestructura y gastos de explotación. Algunos de los factores que son necesarios de tomar en cuenta en un ambiente Cliente/Servidor son: Aumento de la complejidad debido a la conexión de múltiples sistemas heterogéneos. Diversidad de fuentes de datos. Nuevas plataformas (sistemas operativos) y operaciones. Inversión inicial en infraestructura. Formación y creación de especialistas en nuevas herramientas y metodologías. Arquitecturas de aplicaciones y diseño para un entorno distribuido. Nuevas guías de procedimientos operativos. Soporte técnico a los usuarios. La inversión en un sistema Cliente/Servidor tiene las siguientes ventajas: 1. Utilizar los adelantos en el campo de la computación de una forma más rápida. Actualmente, las estaciones de trabajo poseen un considerable poder de cómputo que anteriormente sólo se encontraba en los mainframes o minicomputadoras. 2. Permitir que el procesamiento resida cerca de la fuente de los datos, por lo que el tráfico en la red y el tiempo de respuesta pueden ser reducidos significativamente. 3. Facilitar el uso de interfaces gráficas, las cuales son fáciles de aprender y permiten el rápido desarrollo de aplicaciones atractivas y funcionales. 4. Permitir la heterogeneidad en software y hardware, diferentes arquitecturas con distintos sistemas operativos pueden ser utilizados para el procesamiento. Esta heterogeneidad es lograda a través del uso de estándares. 5. Impulsar la aceptación de sistemas abiertos. 14 Cap. 1. Modelo Cliente /Servidor 1.7 Beneficios de la Arquitectura ClientelServidor Los beneficios obtenidos por la implementación de un sistema Cliente/Servidor pueden ubicarse en alguna de las siguientes categorías: 1. Mayor productividad de los usuarios, debido al uso de interfaces gráficas que permiten accesar e integrar aplicaciones de una forma intuitiva. 2. Incremento en la disponibilidad de software comercial, como procesadores de texto, hojas de cálculo, etc. 3. Cercanía del usuario a las aplicaciones y los datos que son necesarios para su actividad, compartiendo servicios. 4. Mayor disponibilidad de herramientas de desarrollo fáciles de usar, reduciendo con esto la dependencia del departamento de sistemas. 5. Reducción del costo de mantenimiento. 6. Mejoramiento de la utilización de los recursos de cómputo. 7. Incremento de la portabilidad del software. 8. Mejora del incremento de las redes existentes en una empresa. 9. Reducción en el tiempo de desarrollo de las aplicaciones. 1O. Aumento en la productividad de los programadores. 11. Permite a la empresa adaptarse, muy rápidamente, a los cambios en las políticas internas de la compañía, como a los avances de la tecnología, lo cual da a la empresa una ventaja competitiva sobre sus contrincantes. Los beneficios que se derivan de una aplicación Cliente/Servidor dependen, en gran medida de las necesidades del negocio. 1.8 Desventajas de la Arquitectura ClientelServidor 1. Si el Servidor realiza la mayor parte del procesamiento de las aplicaciones, éste puede saturarse y provocar cuellos de botella (bottleneck) al aumentar el número de usuarios. 2. La administración de esta clase de sistemas es más compleja y delicada, debido a que se trabaja en un ambiente distribuido. 3. La curva de aprendizaje puede llevar demasiado tiempo. 15 Cap. I.Modelo Cliente /Servidor 4. Sin una clara definición de las metas y objetivos del sistema se puede llegar a incurrir en costos y tiempos que sobrepasen por mucho a los estimados. 5. Las aplicaciones distribuidas, especialmente las diseñadas para un ambiente cooperativo son más complejas de desarrollar, impiementar y administrar que los centralizados. 16 Cap. 2 Conceptos Generales de COM y DCOM 2.1 Introducción La nueva tecnología en la que se basa Windows NT 4.0 y la implementación de Microsoft de DCOM suponen grandes avances hacia la informática multinivel. Al examinar arquitecturas multinivel, es importante tratar las ventajas de este método con detalle y, además, examinar los campos en los que Windows NT y DCOM pueden mejorarse con herramientas adicionales que les permitan responder a los desafíos del desarrollo en este entorno. Borland es capaz de proporcionar un producto que amplia los servicios ofrecidos por Windows NT 4.0-MIDAS: Multi-tier Distributed Application Services Suite. Con MIDAS, Borland está proporcionando una serie de servicios de aplicación de nivel medio que amplían los estándares del sistema operativo. Estos servicios están diseñados para resolver desafíos de informática distribuida especiales, desde servicios de directorio diseñados para localizar aplicaciones en la red hasta integración de bases de datos y proceso de reglas comerciales. Borland puede proporcionar esta tecnología debido a su tradicional experiencia en herramientas de desarrollo y modelos de componente y gracias a tecnologías llevadas a Borland su división Open Environment. El producto Entera del Open Environment Division proporciona una arquitectura abierta y flexible que durará perfectamente hasta la próxima década. La infraestructura creada con Entera ofrece un entorno dimensionable para desarrollar y distribuir aplicaciones de empresa que integran varios GUI y varias fuentes de datos en un entorno de informática distribuida. 2.2 Creando aplicaciones dimensionables con Windows NT y DCOM Con el lanzamiento de Windows NT 4.0, Microsoft ha proporcionado un nuevo conjunto de tecnologías y servicios para que los desarrolladores creen aplicaciones multinivel, intranet e Internet. Windows NT 4.0 ofrece el núcleo de estas posibilidades mediante DCOM (Distributed Common Object Model: modelo de objeto común distribuido). Como DCOM es una extensión de COM, conviene hablar un poco sobre COM. Las aplicaciones que funcionan en Windows 95 y Windows NT tienen espacios de memoria protegidos. Esto asegura que una aplicación no pueda acceder a la memoria ocupada por otra aplicación. Aunque en general éste es un modelo adecuado, existen razones para proporcionar un nivel de comunicación entre aplicaciones. Este nivel de comunicación es proporcionado en Windows 95 y Windows NT mediante COM. COM ofrece el protocolo que permite a una aplicación interactuar con otra en la misma máquina. La imagen siguiente representa la arquitectura COM. 17 Cap. 2 Conceptos Generales de COM y DCOM Arquitectura COM Ahora que COM ha proporcionado la posibilidad de comunicarse con otra aplicación que funcione en la misma máquina, el siguiente paso es proporcionar la capacidad de comunicarse con una aplicación funcionando en una máquina distinta dentro de la red. Esto es esencialmente lo que ofrece DCOM. La imagen que mostramos a continuación representa gráficamente la arquitectura DCOM: Arquitectura DCOM DCOM ofrece a una organización muchos beneficios que van más allá de proporcionar simplemente la habilidad de crear aplicaciones en red. La sección siguiente resalta alguno de los beneficios de DCOM, y continúa con una explicación sobre alguno de los campos en los que DCOM puede mejorarse con otras herramientas. 18 Cap. 2 Conceptos Generales de COM y DCOM 2.3 Neutralidad de los Lenguajes de Programación Si una aplicación está escrita con Delphi, puede activarse y utilizarse desde una aplicación Visual Basic. Esto evita que los desarrolladores se queden bloqueados utilizando una sola herramienta, lo que les permite seleccionar la herramienta más adecuada para el trabajo. 2.4 Gestión de la conexión DCOM utiliza un contador de referencia para determinar cuántos clientes están conectados a un determinado servidor. Así,cuando un nuevo cliente se añade a la lista, el contador se incrementa y, a la inversa, cuando un cliente se desconecta del servidor de aplicaciones, la referencia disminuye. Cuando el contador de referencia llega a cero, la aplicación se cierra. Cuando un servidor de aplicaciones ya no esté en funcionamiento, DCOM lanzará la aplicación y establecerá el contador de referencia de la manera más adecuada. Si un cliente se desconecta sin que disminuya el contador de referencia, debe existir un modo de que el servidor disminuya el contador de referencia. Esto se lleva a cabo enviando el servidor un "ping" al cliente. Si el servidor no logra hacer llegar al cliente un "ping" tres veces seguidas, la conexión se considerará cerrada y el contador de referencia será ajustado. 2.5 Interfaces múltiples DCOM se implementa fundamentalmente mediante la utilización de interfaces. Las interfaces son los métodos expuestos y las propiedades de un objeto en particular. Puede haber muchas interfaces para el mismo objeto. Esto ofrece la posibilidad de personalizar un objeto sin tener necesariamente que volver a desarrollarlo. Esto es especialmente importante cuando el objeto requiere una funcionalidad adicional que sólo necesitan un subconjunto de los clientes. En esta situación, el desarrollador puede utilizar la misma implementación con distintas interfaces. Una interface puede proporcionar la funcionalidad básica necesaria; el otro puede proporcionar la funcionalidad mejorada. Esto puede llevarse a cabo incluso aunque la implementación real pueda ser exactamente la misma. Integración con otros protocolos de red Como DCOM está basado en sencillos protocolos TCP/IP y RPC, los servidores de aplicación pueden llamarse desde cualquier punto de Internet utilizando TCP/IP básico u otros protocolos basados en TCP (como PPTP --Point to Point Tunneling Protocol--) para usuarios que conectan o HTTP para usuarios de Internet. Soportando el nivel más bajo de interoperabilidad de red, la comunicación en red de DCOM es transparente para las aplicaciones. Esto ofrece muchas opciones de red distintas para el desarrollador para que tome la decisión de elegir la mejor conectividad para la aplicación. A continuación vamos a ver algunos de los campos de DCOM que podrían beneficiarse de la incorporación de otras herramientas. 19 Cap. 2 Conceptos Generales de COM y DCOM 2.6 Independencia en la ubicación y equilibrio de carga Aquí el concepto es que la aplicación cliente no se ocupa de averiguar dónde está situado el servidor de aplicaciones, sólo de que pueda conectarse a él. Como DCOM está dirigido hacia aplicaciones conectadas en red, el Único criterio que se puede aplicar es que la aplicación exista realmente en la red. El modo en que una máquina cliente "encuentra" a un servidor de aplicaciones es localizando las entradas de registro adecuadas en el archivo de registro del cliente. Simplemente cambiar la información de registro del Servidor A al Servidor B hará que el cliente cargue la aplicación en el Servidor B. Cuando una aplicación tiene muchos usuarios, estos pueden dividirse en grupos de usuarios. Por ejemplo, el Grupo 1 podría estar utilizando un servidor de aplicaciones de inventario que está funcionando en el Servidor A mientras que el Grupo 2 puede utilizar la misma aplicación funcionando en el Servidor B. Haciendo esto, la carga puede equilibrarse a lo largo de las distintas máquinas. Este tipo de equilibrio de carga se llama estático, porque los usuarios siempre conectan con el mismo servidor, sea cual sea el número de usuarios que estén conectados. Esto está bien para situaciones sencillas, pero la mayoría de las veces la carga necesita equilibrarse dinámicamente. Teniendo en cuenta el ejemplo de arriba, añadamos un poco de complejidad más realista. En ciertos momentos del día, el Grupo 1 requiere utilizar mucho más el servidor de aplicaciones. En ese mismo momento, las necesidades del Grupo 2 son bajas. Si se utiliza equilibrio de cargas estático, el Servidor 1 estará bastante infrautilizado, mientras que el Servidor 2 estará sobrecargado. Si hubiera una forma de pasar dinámicamente algunos usuarios del Grupo 1 al Servidor 2 en lugar de al Servidor 1, basándose en el tráfico de red existente para cada servidor, la utilización global estaría equilibrada en los dos servidores, dando como resultado un mejor rendim¡ento. DCOM por sí solo no resuelve equilibrio de carga dinámica. No obstante, recomienda que los desarrolladores creen un objeto de referencia para ocuparse de este requisito de aplicación. Borland ha desarrollado un objeto de referencias de este tipo (la tecnología Business ObjectBroker en Delphi 3 ClienüServer y MIDAS). 2.7 Seguridad frente a los fallos y tolerancia a los errores DCOM proporciona soporte básico para la seguridad frente a los errores con las utilidades de "pinging". Esencialmente, esto significa que si un servidor de aplicaciones falla por cualquier razón, DCOM intentará reiniciar la aplicación. Aunque ésta es una función importante, no resuelve momentos en los que el servidor de aplicaciones no puede reiniciarse debido a diversas razones, incluyendo fallos en la red, fallos de hardware, fallos en la aplicación, etc. En la página blanca de Microsoft sobre DCOM, "DCOM Technical Overview", la solución recomendada a un sistema de aplicaciones realmente tolerante a los fallos se describe de la siguiente manera: 20 Cap. 2 Conceptos Generales de COM y DCOM "DCOM facilita la implementación de la tolerancia a los errores. Una técnica es el componente de referencia introducido en la sección anterior. Cuando los clientes detectan el fallo de un componente, vuelven a conectar con el mismo componente de referencia que estableció la primera conexión. El componente de referencia tiene información sobre los servidores que ya no están disponibles y proporciona automáticamente al cliente una nueva muestra del componente funcionando en otra máquina". Aunque DCOM proporciona la infraestructura para crear un sistema así, no se ha implementado en DCOM propiamente dicho. Con Business ObiectBroker y OLEnterprise, los usuarios de Delphi 3 ClienüServer y MIDAS tienen un componente de referencia similar. Este servicio de aplicación funciona tal y como se ha descrito arriba. 2.8 Integración de base de datos Para comprender las cuestiones sobre integración de bases de datos, podemos estudiar los fundamentos de DCOM. DCOM se basa en llamadas a procedimiento remoto (RPC). Hay una limitación en las RPC, como que existe un conjunto limitado de tipos de datos soportados. Estos tipos de datos son los tipos sencillos (por ejemplo enteros, cadenas, arrays, binarios, etc.). Lo que no se soporta es la transferencia de tipos de datos complejos, como los objetos. Aunque los datos de una base de datos suelen entrar en la categoría de los tipos de datos sencillos, los conjuntos de datos en sí no. Algunos fabricantes han aprovechado esta cuestión devolviendo conjuntos de tipos de datos sencillos, un array para cada columna. Aunque esta técnica transporta los datos, la idoneidad para los datos se pierde en la conversión. Es necesario que exista un mecanismo que distribuya un conjunto de datos de base de datos ("Data Sets"), permita al usuario examinar y modificar dicho conjunto de datos y permita al usuario enviar dichas modificaciones de nuevo al objeto comercial de nivel medio y finalmente a la base de datos. Además de devolver los datos de la base de datos, hay también una cuestión acerca de las reglas comerciales. Una función básica de un servidor de bases de datos es la integridad y validación de los datos. Si un servidor de aplicación sólo envía los datos desde la base de datos hasta el cliente, entonces ocurrirá una de dos cosas. Si el desarrollador no realiza codificación adicional en el cliente para evitar obvias infracciones de la integridad de los datos, el usuario final sólo estará informado de dicha infracción de las reglas una vez que hayan enviado los datos de vuelta al servidor de aplicaciones o al SGBDR. Esto dará como resultado una interface de usuario nada sencillo de manejar y tráfico de red innecesario. La alternativa es reprogramar las reglas en la parte de cliente de la aplicación. No obstante, esto tiene otros efectos secundarios. Si la regla cambia, la parte de cliente debe actualizarse. Aunque esto parezca un paso sencillo, donde hay muchas aplicaciones cliente distintas que necesitan ser reconstruidas y muchas máquinas cliente para reinstalar el software, esto es en realidad un proceso complejo y que requiere bastante tiempo. 21 Cap. 2 Conceptos Generales de COM y DCOM Ambos temas sobre integración de bases de datos se resuelven utilizando las tecnologías Remote DataBroker y ConstraintBroker de Borland dentro de Delphi 3 ClientíServer y MIDAS. 2.9 Resumen La implementación que ha realizado Microsoft de DCOM ha supuesto un gran avance hacia el esfuerzo de la informática multinivel. No obstante, hay desafíos adicionales que quedan sin resolver por Windows NT 4.0 y DCOM. Estos campos incluyen equilibrio de cargas, seguridad frente a los fallos, tolerancia a los errores e integración de bases de datos. Los productos de Borland Delphi 3 ClienüServer y MIDAS resuelven estos campos con tecnologías como Business ObjectBroker, Remote DataBroker y ConstraintBroker. 22 Cap. 3. Comunicación Cliente/Servidor bajo el concepto de COM 3.1 Antecedentes COM es una forma para que los diferentes componentes de software se puedan comunicar. Es un estándar binario y de red que permite que dos componentes se comuniquen sin necesidad de saber sobre qué máquina están corriendo, qué sistema operativo están usando o en qué lenguaje están escritos. COM proporciona transparencia de localización (no importa si los componentes son procesos internos DLLs o EXE locales o componentes localizados en otra máquina. Los componentes principales en una comunicación por medio de COM son los objetos y las interfaces. A continuación describiremos cada uno de ellos de una forma técnica 3.2 Objetos COM está basado en objetos, pero no son precisamente como los que conocemos de C++ o de Visual Basic. Para nuestros fines que nos interesa aquí un componente y un objeto es lo mismo, pero se usará el término componente cuando se refiera a la arquitectura de la aplicación mientras que el término objetos se usará cuando se hable de la implementación. Los objetos COM están bien encapsulados. No se puede tener acceso a una implementación interna del objeto, mucho menos se tiene la forma de conocer las estructuras de datos que el objeto podría estar utilizando. Los objetos COM se podrían ver como una caja negra. Todos los detalles de implementación están ocultos. La única forma de tener acceso a un objeto COM es a través de una interface. Por ejemplo, un objeto puede tener una interface IFOO. Esta interface es la Única manera de comunicarse con el objeto. IFoo Objeto con interface, aún no es COM 3.3 Interfaces Las Interfaces son usadas para que se comunique un objeto y un cliente de aquel objeto y el papel que juega COM en esta comunicación es proporcionar transparencia de localización. Cada aplicación tendrá la responsabilidad del manejo de memoria al hacer uso de COM según el tipo específico de la aplicación. 23 Cap. 3. Comunicación Cliente/Servidor bajo el concepto de COM Las interfaces son un conjunto de funciones que se pueden llamar para conseguir que el objeto haga algo. En C++ las interfaces son representadas como una base de clases abstracta, por ejemplo la interface I F 0 0 podría verse como class IFoo virtual void Funcl (void) =O; virtual void Func2 (int nCount) = O; 1 Nótese que puede haber más de una función en una interface y que todas las funciones son funciones virtuales puras, es decir que su implementación no está en la clase IFoo. Las interfaces son contratos fuertemente tipificados entre un cliente y un objeto hablando semánticamente, y para COM, es cualquier estructura donde el objeto expone su funcionalidad a través del mecanismo de interface, que a su vez sigue un estándar binario que permite que un cliente y un objeto interoperen sin considerar el lenguaje de programación usado para implementarlos. Cada interface es un contrato inmutable, como si fuera un grupo funcional que es referido al tiempo de ejecución con un único identificador de interface global que permite a un cliente preguntar a un objeto si este soporta una semántica de interface sin necesidad del encabezado y sin problemas de versiones. El cliente pregunta usando la función Querylnterface de pertenece a la interface IUnknown la cual es la interface base de todos los objetos. El cliente siempre tratará con objetos a través de apuntadores de interface y nunca tendrá acceso directamente al objeto. Una interface no es un objeto, de hecho un objeto puede tener más de una interface si este tiene más de un grupo de funcionalidad que este soporta. La interface se puede visualizar como un contrato entre el componente y el cliente. En otras palabras la interface no sólo define qué funciones están disponibles, sino que también define qué regresa el objeto cuando las funciones son llamadas. Esta definición semántica está en términos del comportamiento del objeto. Por esta razón el contrato tiene que ser documentado fuera del código fuente. Es importante hacerlo notar puesto que el cliente no tendrá porque tener el código fuente. Una interface no es un objeto ni mucho menos es una clase de objetos. En C++ se puede instanciar un objeto de una clase, pero un objeto no se puede instadar con un tipo de interface. En las aplicaciones de C++ las interfaces están definidas como clases de base abstracta. Esto es, la interface es un clase de C++ que sólo tiene la definición o declaración de las funciones miembro, lo que significa que la interface no contiene la implementación de estas funciones, sino Únicamente prescribe la definición de la función para algunas otras clases que implementar (los compiladores de C++ generaran errores cuando se compile el código que intenta instanciar una clase base abstracta). Las aplicaciones C++ implementan objetos COM heredando estos prototipos de funciones para una o más interfaces, predominando todas las funciones de la interface proporcionando una implementación de cada función. Este es como una aplicación COM en C++ implementa las interfaces de un objeto. 24 Cap. 3. Comunicación Cliente/Servidor bajo el concepto de COM Un objeto tendrá que implementar cada una de las funciones de las interfaces que soporte. En COM se usa la palabra interfaz en un sentido diferente al que usa típicamente se usa en C++ o en un lenguaje de programación orientada a objetos. En C++ la interface describe todas las funciones que un objeto soporta y que el cliente de un objeto puede llamar para interactuar con él. En COM una interface se refiere a un grupo predefinido de funciones relacionadas que una clase COM implementa pero no necesariamente representan todas las funciones que una clase soporta. La separación de la funcionalidad de un objeto del grupo es lo que permite que COM y las aplicaciones COM eviten problemas de herencia Una vez que el contrato de interface es publicado contrato es inmutable (ya no hay forma que pueda cambiar debido a que otros componentes dependen de el) Pero, ¿que pasa si se olvidó algo, o si los requerimientos cambian? Una forma par modificar un contrato, es escribir un nuevo contrato. La lista de interfaces del estándar OLE cuenta con muchas interfaces: IClasssFactory, IClassFactory2 y así sucesivamente. Para nuestro ejemplo se tendría una interface llamada I F 0 0 2 y el objeto se vería como: IF002 IFoo a Objeto con 2 interfaces, aún no es COM Por convención el nombre de una interface comienza con una I De esta forma concluimos que los objetos pueden soportar múltiples interfaces. De hecho los objetos COM soportan por lo menos 2 interfaces, la interface IUnknown que se describirá más adelante y una interface que describa lo que se desee que haga el objeto y para que un componente soporte una interface, el objeto tiene que implementar cada uno de los métodos o funciones de las interfaces Por otro lado, estas interfaces tienen algo en común. ¿se tiene que reescribir toda la implementación de la nueva interface que tiene casi exactamente lo mismo que la vieja interface. No, porque COM soporta herencias de interfaces. Mientras no cambien las funciones que existen en IFoo, podemos definir IF002 como sigue Class IF002: public IFoo {//heredando Funcl y Func2 virtual void Func2Ex (double nCount ) = O; 1 Llamando a los métodos definidos en las interfaces Las llamadas a métodos de objetos COM son simplemente llamadas a funciones virtuales de C++ 25 Cap. 3. Comunicación Cliente/Sewidor bajo el concepto de COM Supongamos que tenemos una clase de C++ llamada CFoo que implementa la interface IFoo. Nótese que se hereda de la interface IFoo. Class CFoo : public IFoo { void Funcl ( ) { /* implementación de la función Funcl ...*/ } void Func2 ( ) { /* implementación de la función Func2 ...*/ } El apuntador para hacer referencia a una interface será llamado apuntador de interface. Supóngase que se puede conseguir uno. El código se podría ver como sigue #include void DoFoo ( ) IFoo * pfoo = Obtener-Apuntador Para-El-Objeto-Cfoo ( ); /* llamando a los métodos de la interface */ pfoo -> Funcl (); pfoo -> Func2 ( 5 ); 1 Lo que realmente sucede es : rt. Se hace referencia al apuntador pFoo para buscar el apuntador vtable del objeto rt. Se hace referencia al apuntador vtable y se indexa para buscar la dirección del método que fue llamado. El siguiente diagrama muestra los pasos descritos: I i i Objeto al cual pFoo apunta n i I -_--------b i i Límite del objeto cliente (ai i I CFoo-Fund ( CFoo-FuncE( int nCount) {/*...*O /-J vtable de CFoo ! Llamando a una función vjrtual de C++ a través de un apuntador de inte-rface Recuerde que para cada funcion virtual en C++, se tienen una vtable (tabla virtual) que apunta a aquellas funciones. Y que las llamadas son siempre hechas indexando a la vtable. Nótese que el apuntador es sólo parte del mecanismo del llamado de un objeto que reside en el módulo cliente, y el resto es implementado por el objeto. 26 Cap. 3. Comunicación ClienteíServidor bajo el concepto de COM 3.4 Identificadores en COM Antes de seguir adelante, es necesario tener algunos identificadores para referirse a varias entidades en el mundo COM. Primero es necesario un identificador para el objeto COM. Segundo, se necesitará un identificador para cada interface. Ahora bien, los identificadores deben ser Únicos para todas las máquinas, puesto que no hay manera de saber sobre qué máquina se instalará el componente. En otras palabras estos identificadores deben ser globalmente Únicos. Afortunadamente existen algoritmos y formatos de datos que ayudan a crear tales identificadores. Por ejemplo al usar el número de tarjeta de red de la máquina, junto con la hora y otro dato daría como resultado un identificador Único global. A este tipo de identificadores también se les conoce como GUID* y son creados por un programa llamado GUIDGEN.EXE*. Los GUID's son almacenados en una estructura de 16 bytes (128 bits) dando 2(Iz8)posibles GUID's. En C++ hay tipos de datos definidos por archivos de encabezados de COM para GUID, CLSID * y IDD. Puesto que estas estructuras son muy largas para pasarse por valor, se hará uso de REFCLSID y REFllD como parámetros para pasar los GUID's. Se tiene que crear un CLSID por cada objeto que se escriba y un IID por cada interface que se vaya a crear. Una clase COM es una implementación particular de cierta interface; la implementación consiste de una código máquina que se ejecuta cuando se interactua con una instancia de una clase COM. Un objeto COM está definido por un Único CLSID de 128 bit que asocia una clase objeto a un DLL o EXE en el sistema de archivos 3.5 Interface estándar Todos los objetos en COM, por medio de una interface, permiten a los clientes acceder a 2 tipos de operaciones básicas: 0 Navegar entre las múltiples interfaces de un objeto a través de la función Quervlnterface 0 Controlar el tiempo de vida de los objetos por medio de un mecanismo de conteo con las funciones AddRef & Release Estas operaciones constituyen la interface IUnkown de la cual toda interface hereda. Con la función Querylnterface es un mecanismo con el cual un cliente puede obtener un apuntador de interface para un objeto en particular, puede solicitar apuntadores adicionales de otras interfaces del mismo objeto. Un parámetro de entrada apara el Querylnterface es el IDD que esta siendo solicitada. Si el objeto no soporta esta interface, regresa un error. 27 Cap. 3. Comunicación ClienteíServidor bajo el concepto de COM Querylnterface proporciona una manera robusta y confiable para un componente para indicar que hechos no soporta un contrato dado. Existen 4 métodos a traves de los cuales un cliente obtiene su primer apuntador a interface dado un objeto. Llamar a las funciones COM que crearan un objeto de un tipo predeterminado que es una función que solo regresará un apuntador a una interface en específico para un objeto en específico Llamar a las funciones COM Library API que puede crear un objeto basado en un identificador de clase y que regresa cualquier apuntador a un tipo de interface pedida. 0 Llamar a una función miembro de una interface que crea otro objeto y regresa un apuntador de interface de un objeto separado 0 lmplementar un objeto con una interface a traves de la cual otro objetos pasa su apuntador de interface al cliente directamente. Este es el caso donde el cliente es un objeto implementador y pasa un apuntador a su objeto y a otro objeto para establecer una conexión bidireccional COM define un gran conjunto de interfaces estándares y sus IID's asociados. Por ejemplo la madre de todas las interfaces es la ¡Unknown que tiene un IID 'O0... 46', este está definido por COM y nunca uno se refiere a él directamente, en su lugar se utiliza el símbolo IID-IUnknown, el cual está definido en los encabezados. La interface IUnknown tiene 3 funciones HRESULT Querylnterface (REFIID rid, void ** ppvobject); ULONG AddRef ( ); ULONG Release ( ); Varios de los programas COM estarán hechos usando interfaces estándares. Muchos de ellos estarán proporcionando implementaciones para interfaces estándares de tal forma que otros clientes COM y objetos puedan utilizar el objeto Existen algunas macros usadas en COM para describir el tipo de dato de retorno y la convención de llamado de funciones. Usando estas macros, las declaraciones de arriba se pueden ver como: STDMETHODIMP Querylnterface (REFIID riid, void ** ppvobject); STDMETHODlMP-( ULONG) Add Ref ( ); STDMETHODIMP-(ULONG) Release ( ); 28 Cap. 3. Comunicación Cliente/Servidor bajo el concepto de COM 3.6 Interfaces Personalizados Son las interfaces que uno crea. Uno tienen que crear su propio IID para estas interfaces y definir su propia lista de funciones. En el ejemplo la interface IFoo es una interface custom. Se ha definido un IID llamado IID-lfoo con el valor de '13C0205C-A7531ldl-A52D-0000F8751 BA7' generado por el GUIDGEN. Recordemos la declaración de la clase que originalmente se tenía: class IFoo { virtual void Funcl ( void) = O; virtual void Func2 ( int nCount) =O; 1 Modificaremos esta declaración para ser condescendientes con COM cambiándola a: interface IFoo: IUnknown { virtual HRESULT STDMETHODCALLTYPE Funcl ( void) = O; virtual HRESULT STDMETHODCALLTYPE Func2 ( int nCount) =O; 1 Usando las macros descritas arriba, esto se convierte en: interface IFoo: IUnknown{ STDMETHOD Funcl (void) PURE; STDMETHOD Func2(int nCount) PURE; 1 STDMETHOD usa STDMETHODCALLTYPE el cual esta definido como -stdcall, indicando al compilador que debe generar una función estándar, llamando secuencias de estas funciones. Recuerde que se usaron macros debido a que las definiciones de ellos cambiaran conforme el código se porte a diferentes plataformas. Casi todas las funciones COM regresan un código de error en HRESULT. Este HRESULT es un número de 32-bits, donde el bit de signo se usa para representar éxito o falla y los restantes 31-bits para indicar la facilidad Ó el código de error. Hay que hacer notar que se está derivando IFoo de la interface estándar de COM: IUnknown. Esto significa que cualquier clase que implemente IFoo también necesitará implementar las 3 funciones AddRef, Release y Querylnterface. También la vtabla de IFoo tendrá apuntadores a estas 3 funciones antes de los apuntadores a Funcl y Func2. Esto da un total de 5 funciones en la vtable que se tienen que implementar. Todas las interfaces son derivadas de IUnknown, así que todas las interfaces COM tienen estas 3 funciones más las funciones adicionales de la interface 29 Cap. 3. Comunicación ClienteíServidor bajo el concepto de COM 3.7 El compilador MIDL Pero no se tendrá que escribir la declaración de arriba, esto lo generará el compilador MIDL. Cuando se crea una interface generalmente se utiliza un Leguaje de Descripción de Interface (IDL), así un compilador de un LDI puede generar encabezados de archivos para lenguajes de programación de tal forma que las aplicaciones puedan utilizar esta interface, crear proxy y tuberías de los objetos para proporcionar llamadas de procedimientos remotos y salidas necesarias para hacer RPC a través de la red. Recordemos que los objetos COM pueden ser DLL’s para ser usados como procesos internos, lo que significa que están en el mismo espacio de dirección. Así que si se pasa un apuntador de algún dato a un servidor que es un proceso interno, el servidor puede hacer referencia al apuntador directamente. También un objeto puede ser un servidor local (.EXE), y no es más que un proceso externo o remoto al que se ejecuta en diferente espacio de direcciones. En cualquier momento se va a necesitar pasar el apuntador del objeto a los métodos COM, pero surge el siguiente problema: el apuntador no tiene significado en ningún otro espacio de direcciones, lo que es significativo son los datos a los que apunta este. Estos datos tienen que ser copiados en otro espacio de direcciones. A este proceso de copiar los datos correctos se le llama “marshaling”. COM hace el marshalling en muchos casos, pero para que esto suceda, se necesita decirle además del tipo de apuntador cómo será usado el apuntador. Por ejemplo si el apuntador apunta a un arreglo o una cadena, o un parámetro de entrada solamente. No hay forma de expresar esto en C++. Por razón es necesario un lenguaje llamado IDL que sirve para definir interfaces. MIDL.EXE compila el archivo IDL que se escribe para producir varias salidas. Las salidas serán los archivos que son los encabezados que se incluirán en el código. El código IDL se ve muy similar al anterior, solo que esta vez no se encuentra la palabra virtual. Si nosotros creamos una nueva interface IF002 la cual agrega un nuevo método Func3 a los otros 2 métodos, la definición de la interface se vería como: [ uuid (13C0205C-A753-11dl-A52D-0000F8751BA7)] interface IF002 : lunknown { HRESULT Funcl ( ); HRESULT Func2 (int in-only); HRESULT Func3 ([in, out] int v-inout); 1; Los atributos en un archivo IDL están encerrados por los paréntesis cuadrados ’[ 1’ . Estos siempre aplican a lo que se encuentra inmediatamente después, por ejemplo el atributo uuid de arriba se aplica a la interface, esto es el IID de la interface (UUID es sinónimo de GUID). El atributo [in, out] se aplica al apuntdor y le dice a COM que tendrá que hacer el marshalling un mismo entero tanto como para entrada como para salida cuando se llame a la función Func3. 30 Cap. 3. Comunicación Cliente/Servidor bajo el concepto de COM Existe código IDL para definir solamente el objeto. El fragmento de código para definir nuestro objeto podría verse como [ uuid (13C0205C-A753-11dl-A52D-0000F8751BA7)] CoClassFoo c 1 [default] interface IFoo; Así es como el CLSID es asociado con la clase y cómo es definido el conjunto de interfaces que la clase implementa 31 Cap.4. Creación de un objeto COM y uso de sus Interfaces 4.1 Antecedentes Una vez que el CLSID es asociado con un objeto, se puede crear el objeto, esto es muy fácil sólo con una llamada a una función. IFoo * pfoo= null HRESULT hr =CoCreatelnstances (CLSlD-Foo, NULL, CLSCTX-ALL, IID-IFoo, (void (**) &pFoo); Si CoCreatelnstances tiene éxito éste crea una instancia de un objeto identificado por el GUlD CLSID "CLSID-Foo". Nótese que no hay un apuntador al objeto, en lugar de esto, siempre se refiere a un objeto a través del apuntador de interface. Por esta razón se tiene que especificar qué interface se desea (IlD-IFoo) y pasar el apuntador a CoCreatelnstance para almacenar al apuntador de interface. Los otros dos parámetros no los discutiremos porque nos son importantes en este momento. CoCreatelnstance regresa un HRESULT para indicar si tuvo o no éxito. Así que siempre usaremos una macro SUCEEDED para verificar el resultado. Una vez que el objeto ha sido creado exitosamente ya se puede utilizar el apuntador de interface para llamar a los métodos de interfaces como se muestra enseguida If (SUCCEDED (hr) ) { pfoo->Funcl ( ); pfoo->FuncZ ( 5 ); pfoo->Release ( ); /* debe liberarse la interface una vez usada */ 1 else / creación fallada } Es importante liberar el apuntador de interface una vez que se haya terminado de utilizar, llamando a la función Release. Nótese que puesto que todas las interfaces son derivadas de IUnknown, todas las interfaces soportan Release. El objeto COM es responsable de liberarse así mismo cuando se le diga que lo haga. Si se hubiese olvidado llamar a Release, el objeto estaría perdidizo. Este es un problema muy común en la programación COM. Nótese que solamente se libera la interface si realmente se crea. 32 Cap.4. Creación de un objeto COM y uso de sus Interfaces El siguiente diagrama muestra al nuevo objeto creado. Por convención, IUnknown no es etiquetada. Un objeto COM simple con la interface IUnkown Ahora que se ha implementado la interface IUnknown, se tiene realmente un objeto COM. Si se agrega una interface IF002 al objeto, se tendría un total de 3 interfaces para un sólo objeto. IFoo IF002 0-I Y Un objeto COM que soporta varias interfaces 4.2 GUID's y Registro ¿Cómo encontró COM el código del objeto para crearlo? La respuesta es simple, COM revisó en el registro. Cuando un componente COM es instalado, este tiene que tener una entrada correspondiente en el registro. Para nuestra clase Foo, la entrada se podría ver como HKEY-CLASSES-ROOT CLSlD [ uuid (13C0205C-A753-11d l -A52D-O000F8751BA7)]= "Foo-Class" En HKEY-CLASSES-ROOT\ CLSID hay una entrada para el CLSID de nuestra clase. Así es como CoCreatelnstance busca el nombre del DLL del componente. Cuando se le proporciona el CLSID a CoCreatelnstance este encuentra el nombre del DLL, lo carga y crea el componente Si se conoce el nombre del objeto (ProglD), pero no su CLSID, se puede buscar el CLSID en el registro 33 Cap.4. Creación de un objeto COM y uso de sus Interfaces 4.3 Módulos componentes de clases e interfaces Es común que un módulo DLL o EXE implemente más de un componente COM. Cuando esto suceda, habrá más de una entrada CLSID que se refiera al mismo módulo Un módulo (la básica unidad que se construye y se instala) puede implementar uno o más componentes. Cada componente tendrá su propio CLSID y entrada en el registro que apunte al nombre del archivo del módulo. Cada componente implementa al menos 2 interfaces : IUnknown y la interface que expondrá la funcionalidad del componente. Esta se ve como Módulo 0o.OLL contiene la implementación de tres objetos : Foo, Goo, F002. Cada objeto implementa la interface Iunknown y una o más interfaces adicionales 4.4 Obteniendo otra interface con Querylnterface. Supóngase que se tiene un nuevo y mejorado objeto F 0 0 2 que implementa 2 interfaces customs: IFoo y IF002. Hasta el momento se sabe cómo crear un objeto usando CoCreatelnstance y cómo obtener el apuntador de una de sus 3 interfaces (IFoo, IF002, IUnknown) Pero, ¿cómo se obtiene el apuntador de otra interface del mismo objetos?. No podemos utilizar CoCreatelnstances otra vez, porque se estaría creando un nuevo objeto. Esto es un problema que el método Queylnterface de la interface IUnknown resuelve. Recuérdese que dado que todas las interfaces heredan de IUnknown, todas tienen que implementar el método Querylnterface. Se usa el primer apuntador de interface para llamar al método Querylnterface para obtener el segundo apuntador de interface. 34 Cap.4. Creación de un objeto COM y uso de sus Interfaces IFoo *pfoo= NULL; HRESULT hr =CoCreatelnstances (CLSlD-Foo2, NULL, CLSCTX-ALL, IID-IFoo, (void (**) &pFoo); if (SUCCEEDED ( h r ) { pFoo->Funcl ( ); IF002 * pF002 = NULL; hr = pF002 ->Querylnterface (IID-IFoo2, void (**) &pF002); if (SUCCEEDED ( hr ) { int inoutval =5; pFoo2->Func3 (&inoutval); pF002-> Release ( ); 1 1 pFoo->Release ( ); Nótese que se le pasa a Querylnterface el IID de la interface que se desea y el apuntador donde almacenará el nuevo apuntador de la interface. Una vez que Querylnterface regresa el valor de retorno exitoso, ya se puede utilizar el apuntador de interface para llamar las funciones de interface. Hay que hacer notar que hay que liberar los 2 apuntadores una vez que ya se utilizaron 4.5 Controlando el ciclo de vida del objeto Es responsabilidad del cliente liberar un objeto cuando este objeto ya no esta siendo usado. En un sistema de orientación a objetos el cliente puede hacer esto diciéndole al objeto que se destruya. La dificultad yace en tener que hacer que el objeto sepa cuando este tiene que salvarse para destruirse. Los objetos COM, los cuales son dinámicamente asignados, deben permitirle al cliente decidir cuando el objeto ya no está en uso, ya sean objetos locales o remotos que pueden estar en uso por múltiples clientes al mismo tiempo, el objeto debe esperar hasta que todos los clientes hayan terminado de usarlo antes de liberarse. COM especifica un mecanismo de conteo de referencia para proporcionar este control. Cada objeto contiene un conteo de referencia de 32-bits que mantiene al tanto de cuantos clientes están conectados a él, esto es, cuántos apuntadores existen a cualquiera de sus interfaces de cualquier cliente. AddRef incrementa el conteo y Release lo decrementa. Cuando el conteo llega a cero, la función Release está autorizada a liberar el objeto. 35 Cap.4. Creación de un objeto COM y uso de sus Interfaces Cada vez que un cliente llama a una función que regresa un nuevo apuntador de interface como lo es Querylnteface, la función que ha sido llamada es responsable de incrementar la referencia a través del apuntador de regreso Una instancia de una implementación de interface es simplemente un apuntador a un arreglo de apuntadores a funciones. En realidad un apuntador a una interface es realmente una apuntador a apuntador de una tabla de apuntadores de función. Objetos con múltiples interfaces son capaces de proporcionar mas de una tabla de función 4.6 Interfaces que permiten interoperabilidad Existen 3 propiedades de interfaces para proporcionar estos Polimorfsmo (habilidad de asumir varias formas).- En programación 0.0.describe la habilidad de tener un solo enunciado que invoque a diferentes funciones a diferentes tiempos. Todas las interfaces COM son polimorficas cuando tú llamas a una función usando un apuntador de interface sin especificar que implementación es llamada. Dado que la interface sigue un estándar binario, el cliente sabe cómo usar una interface dada para interactuar con cualquier objetos que soporte esta interface sin preocuparse de cómo el objeto implementa el contrato (interface). Esto permite la interoperabilidad cuando escribes una aplicación que puede cooperar con una aplicación sin saber de antemano quien o qué son ellas. Encapsulación si se tiene implementada una interface, se puede cambiar o actualizar la implementación sin afectar a cualquiera de los clientes de tu clase. Similarmente tu permaneces inmune cuando otros hacen cambios a su implementación La interface ¡Unknown tiene otras 2 funciones: AddRef y Release. La mayoría de los objetos COM mantienen un conteo de referencia. Cuando esta referencia llega a cero, el objeto se libera implícitamente. Cuando se usa Release se libera el apuntador de interface y el objeto se libera a sí mismo en el momento apropiado. AddRef incrementa el conteo de referencia y Release lo decrementa Pero en el ejemplo que hemos estado usando ¿porqué si no se usó AddRef sí se uso Release? Bueno, esto se debe a que cuando se llama a CoCreateInstances, esta función llama a Querylnterface, el cual a su vez llama a AddRef. Uno está obligado a llamar a Release con el mismo apuntador de la interface Se necesita llamar AddRef si se está haciendo una copia del apuntador de interface para que el conteo de referencia de la interface sea el apropiado. 36 Cap.4. Creación de un objeto COM y uso de sus Interfaces ¿Qué sucede cuando se llama a CoCreatelnstances? Cuando se llama a CoCreatelnstances, COM busca el registro para encontrar el CLSID, y este a su vez ayuda a encontrar el archivo DLL Ó EXE que implementa al objeto, Pero no se ha explicado de los detalles de cómo esto sucede. CoCreatelnstances encapsula la siguiente funcionalidad: IClassFactory *pCF; CoGetClassObject (rclsid, dwClsContext, NULL, IID-IClassFactory, (void **) &pCF); Hresult = pCF ->Createlnstance(pUnkOuter,riid, ppvobj); pCF->Release ( ); Como se puede ver, existen 3 pasos. El primer paso es obtener la clase del objeto vía el identificador de interface IID-IClassFactory, después de llama a la función Createlnstance de la interface IClass-Factory de la clase del objeto (los parámetros de este llamado son los pasados en la llamada de CoCreatelnstances. Por ahora se tiene una instancia de nuestro objeto en *ppvObj. Finalmente se libera la clase del objeto. 4.7 Clase objeto La clase objeto es un objeto especial de COM cuyo principal propósito es implementar la interface IClassFactory. Este objeto es especial porque no es creado por CoCreatelnstance como muchos de los objetos COM. Este es creado llamando a CoGetClassObject y además no se preocupa por el tipo de objeto creado, (no le importa si es un servidor in-process o local). La clase objeto maneja todos estas diferencias. Sin embargo, CoGetClassFactory, necesita hacer una búsqueda en el registro para resolver cómo crear o encontrar una clase objeto para el CLSID pedido La clase objeto es un ejemplo del poder de polimorfismo. Se puede llamar a COM API para obtener el objeto y una vez que lo hemos obtenido se puede determinar que este soporte la interface estándar que se necesite (IclassFactory) y poder llamar los métodos de esta interface en este caso, la función sería Createlnstances. Si esto tiene éxito, regresará un apuntador de interface que se refiere a aquella clase. Cada clase objeto está asociado con un CLSlDen particular. Nótese que 1ClassFactory::Createlnstance no tiene a CLSID como parámetro, la clase objeto sabe qué CLSID es, para crearlo. Esto significa que para cada CLSID separado que se tenga, se tiene al menos una clase objeto disponible a crear Además IClassFactory, la clase objeto puede implementar las interfaces que se desee. Por ejemplo se podría definir una interface que permita que ponga los valores por defaults para las instancias de objetos creados de una clase objeto en particular. Nótese que no se garantizó que haya una sola clase objeto para un CLSID dado, así que CoCreateClass se puede encontrar más de una vez. 37 Cap.4. Creación de un objeto COM y uso de sus Interfaces ¿Porqué hay una clase objeto? La razón más importante para requerir la implementación de una clase objeto COM es que COM puede tener una manera polimórfica estándar de crear cualquier tipo de objeto sin pedir que el cliente sepa exactamente los detalles de creación. La clase objeto encapsula este conocimiento. Esto implica que la clase objeto y el objeto real tienen una relación muy cerrada y por lo regular un conocimiento uno del otro. Pero, ¿porqué no tener un esquema más simple?. Por ejemplo tener una función llamada Createlnstance DLL que podría aceptar un CLSID y crear una nueva instancia. Una función tal como esta es más simple que un objeto COM y una IClassFactory La respuesta es que ésta no trabajaría para los EXE’s No solo no se podría exportar funciones de los EXE’s sino que tampoco se podría trabajar bien con objetos remotos. De esta forma cuando se hace de una, una clase objeto, un objeto COM, este toma precauciones de todas las cuestiones de inprocess/outof process Puesto que la clase objeto es un objeto que sabe hacer las cosas bien, crea una instancia del objeto etiquetado. Nótese que una vez que la clase objeto es creada COM queda fuera del cuadro en términos de la creación de instancias. Así que para el primer objeto de un tipo determinado, COM tiene que hacer mucho trabajo. Primero tiene que buscar el CLSID en la lista de clases objeto registrados en el registro si la clase objeto no existe. Si la clase objeto registrado es creado, COM lo crea tal vez incluyendo un DLL o comenzar un EXE. Finalmente COM llama a la IclassFactory::Createlnstance de la correcta clase objeto para crear la instancia. Finalmente, la clase objeto puede soportar maneras adicionales para crear objetos. Tal como la interface IclassFactoriy2 que es usada en lugar de IClassFactory para crear controles con licencia. Estos tipos de controles necesitan que el usuario tenga derecho sobre el control que quiere crear. 4.8 lmplementado la clase objetos. Este es un ejemplo muy sencillo de un objeto COM Esto significa que al menos se tiene que implementar la interface IUnknown. Muchos de los objetos también implementan la interface Iclassfactory que permite la creación de instancias. 38 Cap.4. Creación de un objeto COM y uso de sus Interfaces Se puede tener una clase objeto declarada como sigue: Class CmyClass0bject:public IClassFactory { protected: ULONG m-cRef; public: MyClassObject ( ) : mcRef(0) { }; //funciones miembro de la interfaz Unknown STDMETHODIMP Querylnterface (REFIID, void ** ); STDMETHODIMP-ULOG AddRef (void); STDMETHODlMP-U LOG Release (void); //funciones miembro de la interfaz IclassFactory STDMETHODIMP Createlnstnacie(1Unknown*, REFllD iid, void **) STDMETHODlMP Lockserver(BOOL); Hay varias maneras de crear una clase objeto, ninguna de las cuales implica a CoCreatelnstnaces. Basta con declarar en el código la siguiente línea: CMyClassObject g-cfMyClassObject; Esto significa que el objeto siempre existirá cuando el archivo DLL sea cargado. 4.9 lmplementando los métodos de la clase objeto IUnknown ::AddRef y IUnknown:: Release. La clase objeto es global. Este siempre existe y puede ser destruida con solo descargar el archivo DLL. Puesto que nunca se borra este objeto y puesto que las referencias a la clase objetos no mantiene a un servidor cargado, casi no se utiliza la implementación del conteo de referencias. Sin embargo se puede manejar este conteo de referencias. Si el objeto fue crea dinámicamente, Release podría tener la responsabilidad de liberar al objeto cuando el conteo de referenica llegue a cero. Esto se puede ver como sigue: STDMETHODIMP -(ULONG) cmYcLASSoBJECT:: aDDrEF () { return lnterlockedlncrement (&m-cRef); 1 STDMETHODIMP -(ULONG) CmyClassObject :: AddRef ( ) 1 return InterlockedDecrement(&mcRef); 39 Cap.4. Creación de un objeto COM y uso de sus Interfaces La función Querylnterface de la interface IUnknown. La implementación de Querylnterface de este objeto especial es 100 % estándar debido a que es una clase objeto. STDMETHODIMP CMyClass0bject::Querylnterface(REFIID riid, void *** ppv) { *ppv = NULL; if (rid == IID-IUnknown 11 riid == IID-IclassFactory ) { *ppv =static-cast4classFactory *>this; (static-cast4classFactorry *> *ppv )) ->AddRef () ; return S O K ; 1 1 else return E-NOINTERFACE; La función Createlnstance de la interface IclassFactory puede verse como: STDMETHODIMP CMyClass0bject::Querylnterface(IUnknown * pUnkOut, REFllD iid, void * ppv) { *ppv = NULL; if (punkouter != NULL) return CLASS-E-NOAGGREGATION ; //Creación del objeto CMyObject * pObj = new cMyObject (); if (pObj == NULL) return E-OUTOFM EM0RY; /Obtiene el primer apuntador de interface el cual hace un AddRef HRESULT hr = pOvj ->Querylnterface (iid, ppv); //Borra un objeto si la interfaz no esta disponible //Supone que el conteo de referencias estaba en cero if (FAILED ( hr ) delete pObj; return pObj; 40 Cap.4. Creación de un objeto COM y uso de sus Interfaces Primero que nada, si el apuntador es no null, se crea el objeto debido a que se está preguntado si soporta una agregación. Después asignamos al objeto y se regresa un E-OUTMEMORY si no se puede asignar el objeto a memoria. Después se llama a la función Querylnterface del objeto recientemente creado y regresa un error si no tuvo éxito, de lo contrario regresaría un valor de éxito. Hay diferentes patrones de haces la inicialización de la función Querylnterface del objeto dependiendo de cómo el objeto en si haga su referencia inicial . La función Lockserver de la interface Iclassfactory. Lockserver principalmente incremente y decrementa el seguro y el objeto global . este no intenta liberar el archivo DLL cuando el conteo llega a cero (Si el objeto es un servidor .EXE, el servidor podría darse de baja cuando el conteo de referneica llegase a cero previniendo que no hubiese usuarios interactuando con él) STDMETHODIMP CMyClass0bjetc::LockServer (BOOL flock) { if ( fLock ) Interlockedlncrement (&g-cObjectsAndLocks); else InterlockedIncrement (&g-cO bjectsAndLocks); return hr; 1 41 Cap. 5 Implementación del Objeto 5.1 lmplementando el propio objeto Se ha mostrado la clase objeto que implementa a IclassFactory, esta se puede llamar por medio del método Createlnstance. La forma de hacerlo es por medio de la función new: CMyObject *pObj = new CMyObjectO; Ahora veamos lo que éste objeto hace Ó como se crea. 5.2 El diseño de CmyObject Este objeto implementa cuatro interfaces: IFoo, IF002, lgoo y lunknown(Aunque lunknown se puede considerar como parte de todos los objetos). IF002 es una extensión de IFoo (IFoo mas una nueva función), mientras que IGoo es una interface totalmente separada. Así el diagrama de CMyObject se puede ver de la siguiente forma: moo moa 2 IGOO El Figura I. CMyObject, la cual soporta cuatro interfaces. La interface Ifoo, mostrada anteriormente es: interface IFoo : IUnknown { STDMETHOD Funcl (void) PURE; STDMETHOD Func2(int nCount) PURE; 1; Ahora se usará el IDL para definir las interfaces. Así, el IDL para la interface anterior es: uuid(7BA998DO-C34F-I1D I-A54D-O000F8751BA7) 1 interface IFoo : IUnknown { HRESULT Funcl (); HRESULT Func2([in] int inonly); 1; 42 Cap. 5 Implementación del Objeto La segunda interface, interface independiente, IGoo, se ve de la siguiente forma: [ uuid(OE02BI34-C350-11d l -A54D-O000F8751BA7), 1 interface IGoo : IUnknown { HRESULT Gunc(); 1; La interface rara es IF002, simplemente porque es una extensión de IFoo. ~~id(62F890DA-C361-11 d l -A54D-O000F8751BA7) 1 interface IF002 : IFoo { HRESULT Func3([out, retval] int *pout); 1; Cabe hacer notar que IF002 comprende seis métodos: los tres métodos de IUnknown, los dos métodos de IFoo y Func3. (Por la misma razón, IFoo y IGoo comprenden cinco y cuatro métodos respectivamente) Descripción de lo que hace cada uno de estos métodos: Cuando un objeto es creado, este tendrá un valor interno de 5. Funcl incrementará el valor interno y emitirá un sonido si el nuevo valor es un multiplo de 3. Func2 colocará el valor interno al parámetro que se le pase. Por medio de la interface iFoo3, que es derivada de IF002, se obtiene el valor interno actual. En Visual Basic, esta función es llamada de esta forma: "Text2 = Foo2.Func3" en vez de "Foo2.Func3(Text2)". La interface IGoo es independiente de el valor interno(no así con IFoo é IF002), lo que significa que cualquier objeto puede implementar IGoo sin ninguna de las interfaces IFoo y viceversa. En otras palabras, estas interfaces no estan ligadas. 5.3 lmplementando interfaces multiples usando herencia multiple El objeto implementa 4 interfaces: IFoo, IF002, IGoo y IUnknown. Ahora, siempre y cuando la implementación de Querylnteríace regrese un puntero válido para cada una de estas interfaces, no importa que tan preciso sea nuestro código. Por ejemplo, si se escriben objetos COM en C, se crearía un arreglo de puntero a funciones y Querylnterface regresaría la dirección de un puntero que apunta a vtable. Esto es algo complicado, por lo que no se recomienda usar C para hacer objetos COM. 43 Cap. 5 Implementación del Objeto En C++ existen también una variedad de métodos, uno de estos es tener cada una de las interfaces implementadas por un objeto separado, entonces Querylnterface regresa un puntero para cada objeto. El método mas claro es heredar de cada una de las interfaces el objeto. ATL usa este metodo, y el código siguiente también lo hace. Todo lo que tiene que hacer Querylnterface es regresar el puntero asignarlo a la clase apropiada. La declaración de la implementación de la clase se ve: class CMyObject : public IF002, public IGoo { private: int m-ilnternalValue; ULONG m-refCnt; public: CMyObjectO; virtual -CMyObject(); / I IUnknown STDMETHODIMP Querylnterface(REFIID, void **); STDMETHODIMP-(ULONG) AddRef(void); STDMETHODIMP-(ULONG) Release(void); / I IFoo STDMETHODIMP Funcl (); STDMETHODIMP Func2((/*[in]*/ int inonly); / I IF002 STDMETHODIMP Func3(/*[out, retval]*l int *pout); I/ IGoo STDMETHODIMP Gunc(); 1; Cabe hacer notar que no se hereda explicitamente de Unknown ó IFoo. De la misma manera, no se hereda de IUnknown porque tanto IF002 como IGoo heredan(directamente Ó indirectamente) de IUnknown. Si se hereda directamente de IFoo Ó IUnknown, se crearán ambiguedades, por lo que habrá un error de compilación. Así que la regla es: heredar solo de las clases derivadas. Si alguna otra clase que el objeto implementa hereda de una clase base, se esta también implementando, por lo que no se debe heredar de clases base. De hecho se tienen que implementar todos los métodos. 44 Cap. 5 Implementación del Objeto Diagrama de herencia del objeto: Figura 2. La herencia del objeto. Cabe hacer notar que hay dos caminos de herencia para IUnknown. Si se heredara la implementación de IUnknown, sería un verdadero problema porque tendriamos dos implementaciones de IUnknown para el mismo objeto. Lo mismo sucede con las demás interfaces. Pero IUnknown no tiene ni datos ni funciones, así que solo se heredaría la interface. Cuando se hereda solo la interface para una clase, normalmente se escribe solo una implementación para esas funciones, tipicamente en las clases derivadas. Así solo se escribirá una implementación de Querylnterface, AddRef y Release, y esto estará en CMyObject. Todos los punteros de la vtable de IUnknown apuntaran a la misma Querylnterface, AddRef y Release funciones. Esto es consistente con el comportamiento de las funciones virtuales de C++: cuando se llama a una función virtual, siempre se llama a la implementación disponible derivada. Así la vtable par CMyObject puede verse como sigue: 45 Cap. 5 Implementación del Objeto Castto IUnknovin, IFoo, IFoo2, or CMipbjeci I 1 ( L ( uI- F- II { IFm2 IFm C@Objeci:; Queryinterface CW#ject::A ddRef I m@bj=t Castto lGoo Figura 3. Una posible implementación de una vtable para CMyObject. Cabe hacer notar que los punteros de vtable pointers, aún los de sección de IUnknown de IGoo, apuntan a las funciones de CmyObject Así se puede ver que una implementación de Querylnterface, AddRef y Release satisface todas las interfaces de donde se ha heredado. Esto es muy manejable para IUnknown, pero no es correcto para interfaces no relacionadas. Si se esta implementando un objeto COM con herencia multiple, el método que se escriba será llamado por ambas interfaces. Este es le mayor problema para la implementación de objetos COM, aunque normalmete esto no aparece tan seguido, y cuando aparesca se puede resolver el problema implementando una de las interfaces usando una clase anidada, mientras se usa herencia multiple para el resto de los objetos. Se muestra un diagrama del objeto CMyObject: this staiic-cast4Goo *>(this) FL \table pir for all but Goo r L itable pir for lGoo I m JlntemalVBlue I Figure 4. Un objeto CMyObject. 46 Cap. 5 Implementación del Objeto 5.4 lmplementandoa Querylnterface Ya que se sabe que es lo que hace Querylnterface por que lo hace se presenta el código: STDMETHODIMP CMyObject::Querylnterface(REFllD iid, void **ppv) { *ppv = NULL; if (iid == IID-IUnknown ¡id == IlD-IFoo 11 ¡id == IID-IFoo2) 11 { *ppv = static-cast4Foo2 *>(this); 1 else if (¡id == IID-IGoo) *ppv = static-cast4Goo *>(this); 1 if (*PPV) { AddRef(); return S O K ; 1 else return E-NOINTERFACE; 1 Se llama AddRef se hay éxito en Querylnterface - cuando se da un puntero a una interface, se debe usar AddRef para direccionarlo y el cliente debe liberarlo con con Release cuando este hecho. Cabe hacer notar que cuando el cliente el cliente requiere a IID-IGoo, se esta llamando a AddRef con un puntero diferente del que se regresa al cliente. Con el propósito de dar soporte por interface, los clientes de COM deben de llamar a AddRef y liberar con Release sobre el puntero de interface correcto. 5.5 lmplementando a AddRef y Release La implementación de estas es muy sencilla: STDMETHODIMP-(ULONG) CMyObject::AddRef(void) { return ++m-refCnt; // NOT thread-safe 1 47 Cap. 5 Implementación del Objeto STDMETHODIMP-(ULONG) CMyObject:: Release(void) { --m-refCnt; // NOT thread-safe if (m-refCnt == O) { delete this; return O; // can't return member of deleted object 1 else return m-refcnt; 1 Si se esta soportando operaciones de multihilos, se tiene que usar Interlockedlncrement y InterlockedDecrement. Solo usando los operadores de incremento y decremento es mas eficiente(ATL hace la mas eficiente elección posible automáticamente cuando se le dice que modelo de hilos se va a usar) Release tiene la responsabilidad de destruir el objeto cuando la referencia sea cero, y cuando esto pasa, este debe de regresar cero para indicar que el objeto ya no existe. 5.6 El constructor y destructor Código para el constructor y destructor: CMyObject::CMyObject() : m_ilnternalValue(5), m-refCnt(1) { g-cObjectsAndLocks++; // NOT thread-safe 1 CMy0bject::-CMyObjectO { g-cObjectsAndLocks--; // NOT thread-safe 1 Como es de esperarse, el constructor inicializa el valor interno de las variables miembro, en este caso se coloca m-ilnternalvalue a cinco. 48 Cap. 5 Implementación del Objeto Además, el constructor y destructor tienen dos pequeños trucos. Primero, el constructor inicializa el objeto con un contador de referencias(n0 cero). Paraesto se considera en CMyClassObject::Createlnstance,la cual llama a Release sobre el objeto, para despues hacer el primer Querylnterface. Si el primer Querylnterface tiene exito, este llama a AddRef, la cual incrementa el contador. Si este falla, AddRef no es llamado, así la referenciaso se mantiene. En cualquier caso, Createlnstance llama a Release, la cual decrementa el contador. Si el primer Querylnterface tiene éxito previamente, el contador es entonces uno; Si este falla, el contador se pone en cero y Release borra el objeto. Implementación de 1ClassFactory::Createlnstance: STDMETHODIMP CMyClassObject::Createlnstance(lUnknown *punkouter, REFllD iid, void **ppv) { *ppv=NULL; if (punkouter != NULL) //just say no to aggregation return CLASS-E-N OAGGREGAT1ON; //Create the object CMyObject *pObj = new CMyObjectO; if (pObj == NULL) return E-OUTOFMEMORY; //Obtain the first interface pointer (which does an AddRef) HRESULT hr = pObj->Querylnterface(iid, ppv); // Delete object if interface not available // assume initial ref count was one, not zero pObj->Release(); // back to one if QI OK, deletes if not return hr; 1 El segundo truco es que el constructor y el destructor incrementan y decrementan los objetos globales y el contador de seguridad. Este contador es inicializado con cero cuando el DLL es cargado e incrementado para cada objeto creado(except0 la clase objeto) y cuando es llamada la IClassFactory::LockServer(TRUE). Este es decrementado cuando cada objeto es destruido y cuando es llamado LockServer(FALSE). Es mejor incrementar en el constructor y decrementar en el destructor. Por supuesto que es posible incrementar en Createlnstance y decrementar si se borra el objeto en Release, pero esto no es muy elegante 49 Cap. 5 Implementación del Objeto Para un servidor en proeceso, este contador es solo usado por la función global DIICanUnloadNow: STDAPI DIICanUnloadNow() { if (gcObjectsAndLocks == O) return S-OK; else return S-FALSE; 1 5.7 lmplementando una interface propia Ahora que ya se tienen todos las cosas que necesita COM para funcionar, se pueden implementar métodos propios: STDMETHODIMP CMyObject::Funcl () { m-ilnternalValue++; if (m-ilnternalValue % 3 == O) MessageBeep((U1NT)-I); return S-OK; 1 STDMETHODIMP CMyObject::Func2(/* [in] */ int inonly) c m-ilnternalValue = inonly; return S-OK; 1 I/ IF002 STDMETHODIMP CMyObject::Func3(/* [out, retval] */ int * pout) { MeccageBeep((U1NT)-l); *pout = m-ilnternalvalue; return S-OK; 1 50 Cap. 5 Implementación del Objeto I/ IGoo STDMETHODIMP CMyObject::Gunc() { MessageBeep((UINT)-l); return S-OK; 1 5.8 Contruyendolo Como se ve es muy sencillo construir la aplicación. Para este objeto ejemplo, the only other files you have to write is the IDL file and the linker .DEF file. Ya se ha escrito la mayoria del archivo IDL durante el presente documento, pero se necesita algo mas de código al principio: import "oaidl.idl"; import "ocidl.idl"; And some code to the end, after the interface definitions: [ uuid(7BA998C3-C34F-I1D I -A54D-O000F8751BA7) 1 library NONATLOBJECTLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(2E98593E-C34A-I1D I -A54D-O000F8751BA7) 1 coclass MyObject [default] interface IFoo; interface IF002; interface IGoo; 51 Cap. 5 Implementación del Objeto El primer GUlD (empieza con 7BA9) es la GUlD para la biblioteca de tipos; la segunda (empieza con 2E98) es el CLSID para este objeto. Cabe hacer notar que no se creó el archivo cabecera para las interfaces. MlDL cuidara de esto tecleando en la linea de comando: midl /Oicf /h "NonATL0bject.h" /¡id "NonATLObject-i.c" "NonATLObject.idl" MlDL creará algunos archivos utiles: una biblioteca de tipos NonATLObject.TLB, la cual el cliente usa, el archivo proxy/stub, un archivo cabecera NonATLObject.h, and un archivo que contiene el código necesario para definir el GUIDs (IIDs y CLSID), NonATLObject-i. c. Después se incluye NonATL0bject.h en todos los archivos *.CPP antes de incluir la cabecera. Esta cabecera incluye automaticamente todas las ventanas y cabeceras COM que se necesitaran. Haciendo esto(inc1uir antes que la cabecera), se elimina la necesidad de incluirla en la cabecera. También se necesita incluir NonATLObject-i.c en solamente uno de los archivos *.CPP. Esta contiene la definición de todos los GUIDs. Lo anterior dicho se ve de la siguiente forma: #include "NonATLObject.h" #include "Myobject. h" #include "NonATLObject-i .c" // The global class object CMyClassObject g-cfMyClassObject; // Count of locks and objects ULONG gcObjectsAndLocks = O; // Class members and DII* functions next Finalmente, se definen las funciones DIIGetClassObject y DIICanUnloadNow. miembro para ambas clases Una vez que se ha construido el servidor, se registra este como ya se describió,sustituyendo el correcto GUlD 52 Cap. 5 Implementación del Objeto 5.9 El objeto clase y la fabrica de clases ).Que pasa cuando se llama a Createlnstance? Se ha dicho que cuando se llama a CoCreatelnstance, COM busca el registro del CLSID, ya sea por medio de un DLL o un EXE que implementan el objeto. Los detalles de cómo sucede este, se mostraran enseguida CoCreatelnstance encapsula las siguientes funcionalidades IClassFactory *pCF; CoGetClassObject(rclsid, dwCIsContext, NULL, IID-IClassFactory, (void **)&pCF); riid, ppvobj) hresult = pCF->Createlnstance(pUnkOuter, pCF->Release(); Como se puede ver, hay tres pasos. El primer paso es obtener el objeto clase por medio de su interface IID-IClassFactory. Después, se llama a 1ClassFactory::Createlnstancesobre este objeto clase(Los parámetros para esta llamada son pasados por la llamada de CoCreatelnstance). El parámetro punkouter es usado para reusar un método llamado agregación. Así ahora se tiene un puntero a una instancia del objeto en *ppvObj. Finalmente, se libera el objeto clase. 5.9.1 El objeto clase El objeto clase es un objeto COM especial cuyo propósito principal es implementar la interface IclassFactory, aunque aveces se oirá que este objeto hace referencia a una fabrica de clases Ó aún a la fabrica de objetos clase, pero es más exacto llamarlo como el objeto clase. Este objeto es especial porque no es creado al llamar a CoCreatelnstance o IClassFactory::Createlnstance, como sucede con la mayoria de los objetos COM. En vez de esto, este siempre es creado al llamar a CoGetClassObject. El objeto clase es un grandioso ejemplo de polimorfismo. Se puede llamar a COM API con el fin de obtener el objeto, pero una vez que se haya obtenido este objeto, se puede determinar que este soporta la interface estándar que se necesita IClassFactory y se puede entonces llamar los métodos de la interface, en este caso a 1ClassFactory::Createlnstance. Nótese que no se tiene idea de cómo trabaja Createlnstance. Todo lo que se sabe es que si esta tiene éxito, esta regresará un puntero de interface que apunta hacia el objeto. Es la identidad del objeto clase la que determina la conducta exacta. 53 Cap. 5 Implementación del Objeto Cada instancia del objeto clase esta asociada con un exclusivo CLSID, nótese que 1ClassFactory::Createlnstanceno tiene un CLSID como uno de sus parámetros. En vez de esto, el objeto clase sabe a que referenciar. Esto significa que será necesario al menos un objeto clase para cada CLSID separado que se quiera poder crear. Resumiendo a IClassFactory, el objeto clase puede implementar cualquier interface que este quiera. Por ejemplo, se puede definir una interface que permita colocar defaults para instancias de objetos creados desde un objeto clase particular. Pero nótese que no se esta asegurando que exista solo un objeto clase para un CLSID dado, así que si se llama a CoGetClassObject mas de una vez, se puede obtener punteros de interface a diferentes objetos clase. Y como se puede controlar la creación de objetos clase, se puede definir esto en la implementación. 5.9.2 Porque existe un objeto clase Como ya se ha mostrado, la más importante razón para COM en requerir la implementación de un objeto clase es que COM puede tener una forma polimórfica estándar de crear objetos de cualquier tipo sin requerir que el cliente conozca los detalles completos de la creación. ¿Pero porque no un esquema mas simple?, por ejemplo, se puede imaginar una función en un COM DLL llamada DLLCreatelnstance que aceptara un CLSID y creara una nueva instancia. Una función como esta es ciertamente más simple que un objeto COM y IClassFactory. Pero esto no funcionaría para EXEs. No solo se exportarían funciones desde los EXEs y esto ciertamente no funcionaría bien para objetos remotos. Así que cuando se hace el objeto clase a un objeto COM, COM cuida los detalles. El objeto clase es un objeto COM que sabe como hacer las cosas bien para crear una instancia del objeto principal, nótese que una vez que el objeto clase es creado, COM no participa en lo que respecta a la creación de instancias. Así que para un primer objeto de un particular tipo que es creado, COM tiene que hacer bastante trabajo, tiene que buscar el CLSID en la lista de objetos clase registrados(0 en los registros si es que el objeto clase no existe). Si el objeto clase necesita ser creado, COM lo crea. Finalmente, COM llama a IClassFactory::Createlnstancesobre el objeto clase correcto para crear la instancia. Pero si se conserva el objeto clase fuera, se puede evitar la mayoria del trabajo de las siguientes instancias: simplemente llamando a IC1assFactory::Createlnstancepara hacer objetos adicionales. Esto puede ser tan rápido como llamar al operador new directamente, y mucho mas rápido que dejar que COM genere los objetos. Importante: Si se conserva un objeto clase fuera, se debe de llamar a 1ClassFactory::LockServerpara informarle a COM que mantenga el servidor en memoria. La referencia al objeto clase no 54 Cap. 5 Implementación del Objeto conservará el servidor automáticamente en memoria. Este comportamiento es una excepción al comportamiento normal de COM. SI se falla al accesar al servidor, se puede causar una violación de protección si se intenta accesar el objeto clase después de que el servidor fue descargado. Finalmente, el objeto clase puede soportar formas adicionales de crear objetos, como es la interface IClassFactory2, interface que es usada en vez de IClassFactory para crear controles patentados. Los controles patentados son controles que requieren que el usuario tenga la licencia correcta de ID antes de que el control pueda ser creado. 5.9.3 Otra forma de crear objetos y cuando usarla Si se esta creando solo una instancia de un objeto y se puede usar a IClassFactory para crear el objeto, se puede usar también a CoCreatelnstance (0 CoCreatelnstanceEx, que puede crear objetos remotos). Pero si se esta creando mas de una instancia de un objeto, Ó se necesita usar una interface además de IClassFactory para crear el objeto, se necesita obtener y tal vez mantener un objeto clase. Obtener el objeto clase es fácil; solo hay que hacer lo que CoCreatelnstance hace: llamar a CoGetClassObject. Una vez que se tiene el puntero de interface para el objeto clase, llamar a IClassFactory::LockServer(TRUE)para cargar el servidor en memoria. Así se podrá llamar a IClassFactory::Createlnstancecuando se necesite una nueva instancia. Finalmente, cuando los objetos ya fueron creados, hay que liberar el puntero de interface por medio de la llamada a la función Release y liberar al servidor por medio de la función IClassFactory::LockServer(FALSE). 5.9.4 lmplementando el objeto clase Como el objeto clase es un simple objeto COM, este implementa al menos una interface: IUnknown. Casi todos los objetos clase también implementan a IclassFactory, así que estos pueden crear instancias: class CMyClassObject : public IClassFactory { protected: ULONG m-cRef; public: CMyClassObject() : mcRef(0) { }; //IUnknown members HRESULT Querylnterface(REFIID, void **); ULONG Add Ref(void); ULONG Release(void); 55 Cap. 5 Implementación del Objeto //IClassFactory members HRESULT Createlnstance(1Unknown*, REFllD iid, void **ppv); HRESULT LockServer(BO0L); 1; Por supuesto que esta clase contiene declaraciones para cada función en IClassFactory: Createlnstance y Lockserver. Además de que existen las funciones de IUnknown. Cabe recordar que IClassFactory es derivada de lunknown. 5.9.5 Como es creado este objeto clase Hay una variedad de formas de crear un objeto clase, ninguna de las cuales involucra a CoCreatelnstance. Como solo se necesita una instancia de este objeto y como este es un objeto pequeño sin constructor, se puede declarar solo un objeto global: CMyClassObject g-cfMyClassObject; Esto significa que este objeto siempre existirá cuando el DLL sea cargado. Con la finalidad de implementar IClassFactory::LockServer,se necesitará también un contador global de todos las instancias que no sean instancias de un objeto clase y el número de veces que Lockserver fue llamado: LONG g-cObjectsAndLocks = O; 5.9.6 Como CoGetClassObject obtiene el objeto clase COM llama a una función llamada DIIGetClassObject en el DLL. Se debe de exportar esta función si el DLL contiene COM-creable objetos COM. DllGetClassObject tiene el siguiente prototipo: STDAPI DIIGetClassObject(const CLSID &rclsid, const IID &rid, void ** ppv); COM pasa como parámetros un CLSID y un IID; DllGetClassObject regresa un puntero a la interface pedida en *ppv. Si el objeto clase no puede ser creado ó la interface pedida no existe, es regresado un error en valor de regreso HRESULT (nótese que STDAPI esta definido para regresar un HRESULT). Para servidores EXE, el proceso es diferente: Se debe registrar un objeto calse para cada clase, COM puede crearlas llamando a CoRegisterClassObject para cada objeto clase. Esto coloca el objeto clase en la lista de objetos clase registrados. Cuando el proceso EXE termina, este llama a RevokeClassObject una vez por objeto clase para remover el objeto de la lista. 56 Cap. 5 Implementación del Objeto Nótese que el cómo COM obtiene el objeto clase, depende de si el objeto es implementado por un DLL Ó por un EXE. Si es un DLL, este carga el DLL y llama a DIIGetClassObject. Para un EXE, este carga el EXE y espera hasta que el EXE registre el objeto clase que esta buscando. La DIIGetClassObject puede verse de la siguiente forma: HRESULT DIIGetClassObject(REFCLSlDclsid, REFllD iid, void **ppv) { if (clsid != CLSID-Myobject) // right CLSID? return E-FAIL; // get the interface from the global object HRESULT hr = g-cfMyClassObject.Querylnterface(iid,ppv); if (FAILED(hr)) *ppv = NULL; return hr; 1 Se debe de checar que se pueda ver el CLSID solicitado. Si no, se regresará un E-FAIL. Después, se llama a Querylnterface para verificar la interface solicitada. Si esta falla, se debe de poner el puntero de salida en NULL y regresar a E-NOINTERFACE. Si esta tiene éxito, se regresa S-OK y el puntero de interface. 5.9.7 lmplementando los métodos del objeto clase 5.9.7.1 1Unknown::AddRef y 1Unknown::Release Se tiene un objeto global, este siempre existe y no puede ser destruido(mientras el DLL no sea descargado). Como no se borrará nunca este objeto y como las referencias a los objetos clase no mantienen un servidor cargado, casi no se necesita implementar un contador de referencias. Sin embargo, COM espera que Release regrese cero cuando este en un estado liberado, así que se necesita una mínima implementación del contador de referencias. AddRef y Release son responsables de mantener el contador de referencias en el objeto. Nótese que se tiene una variable de instancia m c R e f inicializada a cero. AddRef y Release solo incrementaran y decrementaran el contador de referencias y regresaran el nuevo valor de este. 57 Cap. 5 Implementación del Objeto Si el objeto es creado dinámicamente, seria responsabilidad de Release de borrar el objeto cuando el contador de referencias llegue a cero. ULONG CMyClassObject::AddRef() { return lnterlockedlncrement(&m_cRef); 1 ULONG CMyClassObject::Release() { return InterlockedDecrement(&m-cRef); 1 En este código se utiliza las funciones de incremento y decremento thread-safe en vez de usar ++m-cRef y --mcRef para entrar en el hábito de usar Ó pensar en operaciones multihilos. 5.9.7.2 1Unknown::Querylnterface La implementación de Querylnterface es 100% estándar para este objeto; no se necesita nada especial solo por ser un objeto clase. Todo lo que se hace es ver si la interface solicitada es una de las dos interfaces solicitadas (IUnknown y IClassFactory) que se soportan, Si sucede esto, se regresa un puntero de interface, con un cast apropiado; y se llama a AddRef con el puntero al contador de referencias. Si no, se regresa un código de error, E-NOINTERFACE. HRESULT CMyClassObject::Querylnterface(REFIID¡id, void ** ppv) { *ppv = NULL; if (¡id == IID-IUnknown==iid 11 ¡id == IlD-IClassFactory) { *ppv = static-cast4ClassFactory *>this; (static-castclClassFactory *>*ppv)->AddRef(); return S-OK; else { *ppv = NULL; // COM Spec requires NULL if failure return E-NO1 NTERFACE; 1 1 58 Cap. 5 Implementación del Objeto 5.9.7.3 1ClassFactory::Createlnstance Este es el corazón del objeto clase; la función que crea instancias. HRESULT CMyClassObject::Create1nstance (IUnknown *punkOuter, REFllD ¡id, void ** ppv) *ppv=NULL; if (punkouter != NULL) //just say no to aggregation return CLASS-E-NOAGGREGATION; //Create the object CMyClassObject *pObj = new CMyObjectO; if (pObj == NULL) return EOUTOFMEMORY; //Obtain the first interface pointer (which does an AddRef) HRESULT hr = pObj->Querylnterface(iid, ppv); // Delete object if interface not available if (FA1LED(hr)) delete pObj; return hr; 1 Primero, no se soporta agregación, por lo que si el puntero no es NULL, se puede crear el objeto porque se esta siendo solicitado para soportar agregación. Después, se autoriza el objeto y se regresa un E-OUTOFMEMORY si no se puede. Después, se llama a Querylnterface con el nuevo objeto creado para obtener un puntero de interface para regresar. Si esto falla, se borra el objeto y se regresa un código de error. Si esto tiene éxito, se regresa código de Querylnterface. Nótese que Querylnterface llamará a AddRef si tiene éxito, regresando un contador de referencias correcto para el objeto. 59 ~ Cap. 5 Implementación del Objeto Nótese también que no se incrementó ni el contador del objeto y de lock, gcObjectsAndLocks. Se pudo haber hecho esto si la creación hubiese tenido éxito, pero tendríamos que decrementarlo tanto en el Release del objeto Ó en su destructor. 5.9.7.4 IClassFactory::LockServer Lockserver incrementa y decrementa el contador del objeto y lock. Este no intenta liberar el DLL cuando el contador llega a cero. (Si este fuera un servidor EXE, el servidor sería apagado cuando el contador llegara a cero.) HRESULT CMyClassObject::LockServer(BOOLflock) { if (fLock) InterlockedIncrement(&gcObjectsAnd Locks); else lnterlockedDecrement(&g-CObjectsAndLockc); return NOERROR; 1 5.9.7.5 DllCanUnloadNow COM llamará a DllCanUnloadNow para decidir si descarga ó no un DLL. Se regresa simplemente un S-OK si hay que descargarlo, S-FALSE si no. HRESULT DIICanUnloadNow() { if (gcObjectsAndLocks == O) return S-OK; else return S-FALSE; 1 5.9.8 Usando el objeto desde Visual Basic Primero, tenemos que agregar una referencia hacia el objeto en el project de visual basic, esto se hace por medio del submenú de References... que se encuentra en le menú Projects. 60 Cap. 5 Implementación del Objeto Después se diseña una forma con un botón para llamar a cada método y un campo de texto para mostrar el valor actual. Finalmente, se escribe el código necesario para accesar el objeto. Primero, en la sección de declaraciones generales se declara una referencia una referencia al objeto: 61 Cap. 5 Implementación del Objeto Private obj As MyObject Luego se crea el objeto actual en el método Load para la forma: Private Sub Form-Load() Set obj = New MyObject End Sub Esto causa que Visual Basic llame a I CoCreatelnstance para crear el objeto. Ahora que el objeto ha sido creado, se agrega un manejador para llamar los métodos Funcl y Func2 de la interface por default IFoo: Private Sub Funcl IncBeep3_Click() Obj.Func1 End Sub Private Sub Func2Set-Click() If IsNumeric(Text1) Then obj.Func2 (Textl) End Sub Para llamar métodos de otras interfaces, se tiene que obtener acceso a la interface. Esto se hace creando una variable del tipo autorizado para la interface, y luego colocarla apuntando al objeto (Cuando se hace esto, Visual Basic llama a Querylnterface sobre el objeto). Para cambiar interfaces se hace de la siguiente forma: Dim F002 As IF002 ' switch interfaces Set F002 = obj Después se puede llama a los métodos de IF002 usando la referencia de objeto F002. Sabiendo esto, se puede entender el código el código para accesar los otros métodos del objeto. Private Sub Func3BeepGet-Click() Dim F002 As IF002 switch interfaces Set F002 = obj Textl = Foo2.Func3 End Sub I 62 Cap. 5 Implementación del Objeto Private Sub GuncBeep-Click() Dim Goo As IGoo switch interfaces Set Goo = obj Goo.Gunc End Sub Finalmente, se agrega un manejador para el método "Increment Text Box": Private Sub IncTextBox-Click() If IsNumeric(Text1) Then Textl = Textl + 1 End Sub Si se es usuario del enlace tardío(late binding), se debe considerar esto: se puede usar enlace tardio para accesar el objeto, pero pero solo se podría accesar la interface por default(1Foo). Enlace tardío no funciona bien para objetos que utilizan múltiples interfaces, además que tiene un lento funcionamiento. 5.9.9 Usando el objeto desde Visual J++ Es casi tan sencillo como usarlo desde Visual C++ Ó Visual Basic. Primero, se debe de crear un archivo de clase especial(*.class) que represente el objeto COM. Esto se hace por medio del wizard de la librería de tipos de Java(Java Type Library Wizard) que se encuentra en menú Tools del Visual Studio. MSNBC News Browser Type Library 2 3 UNameOCX OLE Control module OPlDFetch 1 O Type Library port2 1 O Type Library 63 Cap. 5 Implementación del Objeto Esto crea un archivo de clase que es creado en el directorio trustlib (en el mismo subdirectorio de las demás clases de Java. La ventana resultante tiene la sentencia de import que se debe de copiar y pegar en el archivo *.java. Esta también tiene una referencia hacia el archivo summary.txt que contiene una representación textual de la librería de clases. No compilar este archivo; con esto el archivo *.class ha sido creado. En este caso la sentencia import tiene "import nonatlobject.*;". Se debe de insertar esto en la cabecera del archivo *.Java. Una vez hecho esto, se puede crear y usar el objeto. El objeto se crea por medio de una simple llamada a la función new: IFoo myObj = new Myobject(); Nótese que se creo al objeto MyObject, pero se asigno a la referencia de objeto IFoo. No se puede usar el objeto como un MyObject en Visual J++- Este no reconocería ó soportaría el concepto de una interface por default. En este punto, se puede llamar a los métodos de Ifoo: myObj.Func2(5); myObj.Funcl(); myObj.Func1(); myObj.Funcl(); // sets // increments and beeps // increments // increments Si se desea llamar a los métodos de IF002 o IGoo, se tiene que crear una nueva referencia a objeto y asignar el objeto a los métodos: IF002 myFoo2 = (IFoo2)myObj; System.out.println("Value is + myFoo2.Func3() + (8?)"); 'I I' IGoo myGoo = (IGoo)myFoo2; myGoo.Gunc(); // beeps 64 Cap. 6 Ambiente Cliente/Servidor bajo COM 6.1 Antecedentes El Cliente es cualquier pedazo de código que de alguna manera obtiene un apuntador a través del cual puede tener acceso a los servicios de un objeto y luego invoca estos servicios cuando sea necesario. El Servidor es cualquier pedazo de código que implementa el objeto y estructuras de tal forma que la Librería COM pueda hacer corresponder esta implementación con el identificador de clase. La participación de un identificador de clase es lo que diferencia un Servidor de un implementador más general de objetos. La librería COM utiliza el CLSID para proporcionar el servicio de la implementación a clientes. El Cliente sólo necesita decirle a COM el CLSID que desea y el tipo de Servidor, COM localiza la implementación de la clase y estableces una conexión entre esta y el Cliente 6.2 Clientes y Servidores COM Cuando una aplicación pasa un CLSID a COM y pregunta por un objeto instanciado es un Cliente COM. Un Cliente COM siempre pide a COM instanciar objetos de la misma forma. El método más simple para crear un objeto es con la función COM CoCreatelnstances. Este crea un objeto de un CLSID dado y regresa un apuntador a interface de cualquier tipo que el Cliente pide. Existen 2 tipos de servidores objetos 0 0 DLL En este caso el Servidor es implementado en un modulo que puede ser cargado y que se ejecutará dentro del espació de direcciones del Cliente EXE El Servidor es implementado como un modulo ejecutable aparte Puesto que COM contempla objetos distribuidos, esto también contempla 2 tipos básicos de servidores para implementar con máquinas remotas. Para permitir que las aplicaciones Cliente activen objetos remotos COM define el Manejo de Control de Servicio (SCM) Un Servidor tiene la responsabilidad de implementar la fabrica de clases, de implementar la clases de objetos que la fabrica manufacturará, exponiendo la fabrica de clases a COM y proporcionar el descargamiento del Servidor bajo condiciones correctas. Para que el Servidor logre estos requerimientos, depende si el Servidor está implementado como un DLL o un EXE 65 Cap. 6 Ambiente ClienteíServidor bajo COM 6.3 La Librería COM y el Manejo de Control de Servicio La Biblioteca de COM es una implementación estándar de las funciones API definas en COM para soportar la comunicación entre objetos y clientes. La biblioteca COM es la que hace que todo trabaje transparentemente a través de RPC. Si COM determinar que se tiene que establecer una comunicación entre un Cliente y un Servidor (local o remoto), este crea un objeto proxy que actúa como un objeto in-process para el Cliente. Estos proxies hablan con los objetos stubs que están en el mismo proceso como un Servidor y pueden llamar al Servidor directamente. Los stubs recogen las llamadas RPC de los proxy y las convierten en llamadas de funciones para el objeto real, luego pasan los valores de regreso a los proxy vía RPC, los cuales se los entregan al Cliente. El mecanismo RPC esta basado en el mecanismo estándar DCE de llamadas de procedimientos remotos. 6.4 Arquitectura para objetos distribuidos Una arquitectura COM para la objetos distribuidos es similar a la arquitectura remota, Cuando un Cliente desea conectarse a un objeto del Servidor, el nombre del Servidor es almacenado en el registro del sistema. Con objetos distribuidos, el Servidor puede ser implementado como un objetos in-proces .DLL o un modulo local ejecutable o como un modo ejecutable remoto o un DLL corriendo remotamente. EL SCM tiene la responsabilidad de localizar al Servidor y correrlo Hacer una llamada a un método de interface en un objeto remoto implica la cooperación de varios componentes. La interface proxy es un pedazo de código específico de interface que reside en espacio de los procesos del Cliente y prepara los parámetros para transmisión. Este los ordena para que ellos puedan ser reconstruidos y entendidos en el procesos que los recibe. También la interface de los stub es un pedazo de código que reside en el espacio del proceso y hace el trabajo inverso al del proxy. El stub desempaca o desenvuelve los parámetros enviados y los manda hacia el Servidor. También empaqueta la información de contestación para enviarlos de regreso al Cliente. La transmisión real de los datos a través de la red es manejado por las librerías de RPC a tiempo de ejecución y por el canal, parte de la librerías de COM. El canal trabaja transparentemente con diferentes tipos de canales y soporta tanto aplicaciones de un sólo hilo o multi-hilos Este asegura que cuando una petición del Cliente es hecha, el Servidor apropiado este conectado y listo para recibir tal petición. SCM mantiene una base de datos de información de clases basadas en e registro del sistema que el Cliente. Cuando un Cliente hace una petición para crear un objeto de la clase CLSID; la biblioteca COM contacta al local SCM y pide que el Servidor apropiado sea localizado o lanzado y se regresa la fábrica de clases a la librería COM. Después de eso, la librería COM o el Cliente pueden pedir a la fábrica de clases crear un objeto. 66 Cap. 6 Ambiente Cliente/Servidor bajo COM La acción tomada del SCM depende del tipo del Servidor de los objetos que está registrado en el CLSDI. En proceso. El SCM regresa la ruta del archivo DLL que contiene la implementación del Servidor de objetos. La librería COM carga el DLL y pregunta por el apuntador de interface de la fábrica de objetos. Si es local, el SCM ejecuta el Servidor local el cual registra un fábrica de clases en marcha. El apuntador está disponible a COM. Si es remoto. El SCM local contacta al SCM que corre en la computadora remota y remite la petición al SCM remoto. EL SCM remoto lanza al Servidor el cual registra una fabrica de clase como un Servidor local con COM en la máquina remota. EL SMC remoto mantiene una conexión de la fábrica de clases y regresa una conexión RPC al SCM local, el cual corresponde a la fábrica de clases remota. El SCM local regresa la conexión a COM el cual crea una fabrica de clases proxy el cual internamente remitirá peticiones al SCM remoto vía la conexión RPC. 6.5 Objetos Conectables y Eventos En el contexto de la relación Cliente-objeto(Servidor), se supone que el objeto escucha lo que el Cliente tiene que decir. En otras partes las interfaces entrantes y sus funciones miembros reciben las entradas de afuera. COM también define mecanismos donde los objetos puedan soportar interfaces de salidas. Las interfaces de salida permiten que los objetos tienen 2 formas de conversación con los clientes. Cuando 1 Cliente soporta una o más interface de salida, se dice que es un objeto conectable. Uno de los muchos usos de las interfaces de salida es la notificación de eventos. Un objeto conectable, también se le conoce como una fuente. Cada interface está compuesta de distintas funciones miembros, y cada función representa un evento, una notificación o una petición. Los eventos y la notificación son conceptos equivalentes y términos intercambiables ya que ambos son usados para decirle al Cliente que algo interesante sucedió en el objeto. Los eventos y notificaciones difieren de una petición en que el objeto espera una respuesta del Cliente. Una petición, por otro lado, es como un objeto solicita al Cliente una pregunta y espera una respuesta. En todos los caso, debe haber algún Cliente escuche lo que el objeto tiene que decir y usa la información sabiamente. Lo que realmente implementa estas interfaces son llamados sinks. El sink es lo que el Cliente del objeto usa para escuchar lo del objeto. La solución del problema de integración es un nivel de indirección: un sistema de archivos dentro de un archivo. En lugar de requerir que una larga secuencia contigua de bytes en el disco sean manipulados por un sólo archivo manejador con un sólo apuntador de búsqueda, COM define como tratar un Único sistema de archivos como una colección estructurada de 2 tipos de objetos (almacenajes) que actúan como directorios y archivos respectivamente 67 Cap. 6 Ambiente Cliente/Servidor bajo COM Dentro de la definición de almacenaje persistente de COM hay 2 tipos de elementos de almacenamiento: los objetos de almacenamiento y los objetos flujos, estos objetos son objetos generalmente implementados por las Librería COM por sí misma, las aplicaciones rara vez necesitan implementarlos por sí misma. Estos objetos al igual que otros en COM, implementan interfaces IStream para objetos de flujo y Istorage para objetos de almacenamiento. Un objeto de flujo es conceptualmente equivalente a un archivo de disco. El flujo es el componente básico del sistema de archivos en el cual los datos viven y cada flujo por sí mismo tiene derechos de acceso y un Único apuntador de búsqueda. Por medio de la interface IStream, el flujo puede ser mandado a leer, escribir, buscar o ejecutar unas cuantas operaciones de sobre sus datos. Los flujos osn nombrados al usar una cadena de texto y puede contener cualquier estructura interna que se desee debido a que ellos son simplemente un flujo plano de bytes. Un objeto de almacenamiento es conceptualmente equivalente a un directorio. Cada almacenamiento, al igual que un directorio puede contener cualquier número de sub-almacenamiento (sub-directorios) y cualquier número de flujos(archivos).Además cada almacenamiento tiene sus propios derechos de accesos. La interface Istorage describe las capacidades del objeto de almacenamiento tal como enumerar los elementos (dir), mover, copiar, renombrar, crear, destruir, etc. Un objeto de almacenamiento no puede almacenar datos definidos por una aplicación excepto que implícitamente almacene los nombres de los elementos (almacenamientos y flujos) contenidos dentro de él. Los objetos de almacenamientos y flujos son compatibles entre procesos. Este es una característica clave que habilita objetos que corren en in-process ó out-of-process. Puesto que COM esta cargado en cada proceso separadamente, este debe de usar algún sistema operativo que soporte mecanismo de memoria compartida para comunicar entre procesos de elementos abiertos y sus modos de accesos. Todo objeto de almacenamiento y flujo es un archivo estructurado tiene un nombre de carácter en específico para identificarlo. Estos nombres son usados para decirle a Istorage qué elementos en el almacenamiento para abrir, destruir, mover, copiar, renombrar, etc. Dependiendo del componente, Cliente u objeto realmente define y almacena estos nombres, convenciones diferentes y poner restricciones. Los nombres de los elementos contenidos en los objetos de almacenamiento son manejados por la implementación del objeto de almacenamiento en cuestión. Todas las implementaciones de objetos de almacenamientos deben por lo menos soportar nombres de 32 caracteres de longitud, algunas irnplementaciones podrían escoger la longitud de los nombres. 68 Cap. 6 Ambiente Cliente/Servidor bajo COM Los nombres de los elementos dentro de un objeto de almacenamiento debe cumplir ciertas convenciones: 0 0 no pueden contener / \ , : Ó ! . & .. están reservados Los elementos de almacenamiento y flujo soportan 2 modos de acceso: directo y transaccional. Los cambios son hechos inmediatamente y permanentemente en modo directo, mientras que en modo transaccional los cambios permanecen en buffers de tal forma que ellos podrían ser salvados (comit) o revertidos cuando las modificaciones se acompleten. Por naturaleza, el almacenamiento estructurado de COM separa las aplicaciones de la composición de información dentro de un archivo dado. Todo elemento de información de este archivo tiene acceso de usar funciones e interfaces implementadas por COM. Debido a que la implementación es central, un archivo generado por alguna aplicación usando esta estructura, puede ser visto por cualquier otra pieza de código, tal como un sistema shell. En otras palabras, cualquier pedazo de código en el sistema puede usar COM para ver la jerarquía total de los elementos dentro de un archivo estructurado simplemente navegando con la interface Istorage el cual proporciona servicios de directorio. Si un pedazo de código también sabe que formato y significado de un flujo en específico que tiene un cierto nombre, este podría abrir el flujo y hacer uso de la información de él, sin tener que correr la aplicación que escribió al archivo. Este es una poderosa herramienta de consulta que ayuda a los usuarios a buscar información en sus computadoras o aun en la red. Para que esto realmente suceda se requiere estandarizar ciertos nombres de flujos y el formato de aquellos flujos tal forma que el shell del sistema pueda abrir los flujos y ejecutar consultas de esta información Dado que COM permite que un objeto se lea y se escriba para almacenarse, debe haber una manera en la cual el Cliente le dice al Cliente qué hacer. Esta forma es una interface adicional que forma un contrato de almacenamiento entre el Cliente y los objetos. Cuando un Cliente desea consulta al objeto para una de las interfaces persistentes relacionadas. Las interfaces que los objetos pueden implementar, es cualquier combinación, son: Persitstorage. El objeto puede leer y escribir su estado persistente para un objeto de almacenamiento. El Cliente proporciona el objeto con un apuntador Istorage por medio de esta interface. Esta es la interface IPersist que incluye una semántica para accesos de incremento 69 Cap. 6 Ambiente Cliente/Servidor bajo COM El objeto IPersistStream puede leer y escribir su estado persistente a un archivo en es1 sistema directamente Esta interface no implica Istorage o el lstream a menos que el archivo accese por medio de estas interfaces, pero el IPersistFile no tiene semántica relacionada con tales estructuras. El Cliente simplemente proporciona al objeto de un archivo nombre y ordenes para salvar o cargar, el objeto lo hace si es necesario para llenar el requisito. Un moniker es simplemente un objeto que soporta una interface lmoniker (IPersistStream). La forma persistente de un moniker incluye los datos comprimiendo su nombre y el CLSID de su implementación la cual es usada durante el cargado del proceso. Esto permite que nuevos tipos de moniker puede ser creados trasparentemente para el Cliente. La función de enlace lmoniker toma como parámetro al identificador de interface por el cual el Cliente desea hablar al límite del objeto, corre cualquier algoritmo que sea necesario par localizar al objeto, regresa un apuntador del tipo de interface al Cliente. El Cliente también pide enlazarse al almacenamiento del objeto 6.6 Transferencia de Datos Uniforme COM proporciona interfaces para intercambio de datos entre aplicaciones. Esta tecnología es la Transferencia de Datos Uniforme, el cual proporciona la funcionalidad para representar la transferencia de datos a través de un sola implementación de un objeto de datos. Los objetos de datos implementan una interface llamada IDataObject la cual abarca las operaciones estándares de obtenerlponer datos y consultar/enumerar formatos así como las funciones por medio de las cuales un Cliente de un objeto de datos puede establecer una notificación de loop para detectar cambios de datos en el objeto. Además esta tecnología habilita el uso de más ricas descripciones para los formatos de datos y el uso de cualquier almacenamiento virtual La interface IDataObject separa todas las operaciones comunes de intercambio de lo que es llamada un protocolo de transferencia. Con Uniform Transferencia de Datos, todos los protocolos están relacionado con intercambio de un apuntador a la interface IDataObject El Servidor solamente implementa un objeto de datos el cual es utilizable en cualquier protocolo de intercambio y esto es todo. El Cliente necesita implementar un pedazo de código para pedir datos del objeto de datos una vez que este recibe un apuntador a la interface IDataObject de cualquier protocolo. Una vez que el apuntador de intercambio ha ocurrido, ambos lados tratan de intercambiar datos en un moda por medio del IDataObject. 70 Cap. 6 Ambiente Cliente/Servidor bajo COM Esta uniformidad no solamente reduce el código necesario para generar o consumir datos, sino que también simplifica el código necesario para trabajar con el protocolo en sí. 6.7 Formatos de datos y medios de transferencia Antes del Transferencia de Datos Uniforme, prácticamente todos los protocolos estándares fueron bastante débiles para describir los datos que estaban siendo transferidos y por lo regular se requería que el intercambio ocurriera a través de una memoria global. El problema con el formato del clipboard es que este puede solamente describir la estructura de los datos, esto es, identifica la composición de los bits. Por ejemplo el formatos CF-TEXT describe un texto ASCII, el CFBITMAP describe un dispositivo dependiente de un mapa de bis y así tanto colores como tal dimensiones, pero fue incapaz de describir el mecanismo de sobre que depende. Además ninguno de estos mecanismo o dispositivos dio alguna indicación de Io que realmente estaba en los datos, tal como la cantidad de detalles, si era un mapa de bit o un metafile de imágenes llenas. El problema con el uso de la memoria global como un medio de transferencia es aparente cuando una gran cantidad de datos es intercambiado. Restringiendo los intercambios a la memoria global significa que ninguna aplicación puede seleccionar los datos de intercambio que están en el disco cuando esta vaya a residir en disco, aún cuando sea manipulado y vaya a usar memoria virtual. Esto podría ser mucho más eficiente que permitir que el origen de los datos indique que el intercambio sucede en disco in primer lugar en lugar de forzar los 20 MB de datos por medio de un cuello de botella en memoria virtual A veces se necesita comenzar el proceso con el comienzo de largo conjunto de datos antes de que el fin del conjunto de datos haya alcanzado la computadora destino. Para alcanzar esto, alguna abstracción sobre el medio por el cual los datos son transferidos es necesitada. Para resolver este problema, COM define 2 estructuras de datos FORMATECTC y STGMEDIUM. El primero es un formato clipboard mejor, por que la estructura no solo contiene un formato de clipboard sino que también contiene una descripción del mecanismo, una descripción detallada (contenido, etc.) y una bandera que indica qué dispositivo de almacenamiento es usado para una interpretación en particular. Dos estructuras FORMATETC que difieren solamente por el medio de almacenamiento, son 2 diferentes formatos. EL STGMEDIUM es entonces mejor para el manejo global de memoria, el cual tiene una bandera para indicar el medio además del apuntador o manejo 71 Cap. 6 Ambiente Cliente/Servidor bajo COM de cualquiera que sea necesario para tener acceso al medio real y conseguir los datos. Dos estructuras STGMEDIUM pueden indicar diferentes medios y tener diferentes referencias a los datos, pero estos medios pueden fácilmente obtener los mismos datos. FORMATECT es lo que un Cliente utiliza para indicar el tipo de datos que desea de una fuente de datos (objeto o Servidor) y es usado por la fuente para describir qué formatos puede proporcionar. FORMATECT puede describir Prácticamente cualquier dato, incluyendo otros objetos tal como un monikers. Un Cliente puede pedir un objeto de datos para una enumeración de sus formatos pidiendo al objeto de datos una interface IEnumFORMATECT. STGMEDIUM significa que la fuente de datos y los consumidores pueden ahora escoger el uso del más eficiente medio de intercambio en una base de ***Si los datos son muy largos, esto podrían ser guardados en disco, la fuente de datos puede indicar un medio de disco basado en su formato preferido, solamente usando la memoria global como respaldo si esto es todo lo que el Cliente entiende. Esto tiene el beneficio de usar el mejor medio para los intercambios por default, además mejora la ejecución de intercambios entre las aplicaciones En el peor de los casos, los mecanismos de COM podría ser tan buenos como cualquier protocolo de transferencia de memoria global disponible hoy en día, y en el mejor, los intercambios de datos podrías ser casi instantáneos aún con muchos datos. Nota que 2 medios potenciales de almacenamiento que pueden ser usados en intercambio de datos son los objetos de almacenamiento y los objetos de flujo 6.8 Responsabilidades de una aplicación COM 0 0 o Verificar que la Librería COM sea una versión compatible con la función COM CoBuilVersion Inicializar las librería COM antes de usar cualquier otra función, llamando la función Colnitialize Desinicializarse de la Librería COM con la función CoUninitializeg 72 Cap. 7 Aplicación 7.1 Objetivo El objetivo de esta aplicación es implementar un modelo Cliente/Servidor utilizando COM, ya que este nos permite que la comunicación entre estos dos componentes sea transparente (es decir, que el usuario no sabe que se comunica con la Base de Datos a través de un objeto), segura, independientemente del leguaje de programación en el cual se implementa cada uno. Hay que tener presente que la utilización de COM en una aplicación que realice accesos a Bases de datos no es la más optima, pero debido a que las Bases de Datos son más familiares para cualquier programador se decidió implementar este tipo de aplicación. 7.2 Descripción El Sistema se encarga del manejo de información de un Centro de Renta de Video, para el cual se construyó una Base de Datos en Access 97 y se implementó en Visual Basic Versión 5.0 Entrepise, bajo el modelo Cliente/Servidor. El Servidor (Objeto COM) es el que se encarga del acceso y manejo a la Base de Datos, mediante sentencias SQL. El Cliente hace uso de ese objeto a través de peticiones (consultas, inserciones, etc.), cabe mencionar que el Servidor puede tener varias instancias para atender a varios Clientes a la vez. Con el objetivo de tener integridad y validación de la información en la Base de Datos, se implementó en el Servidor la concurrencia, se asignaron roles a los diferentes usuarios (Clientes), a demás de que el Servidor controla el acceso a los datos que están siendo utilizados por otra instancia. Para que el Servidor pudiese manejar las diferentes instancias, sin necesidad de duplicarse, se implementó como un ActiveXEXE en Visual Basic y el Cliente como un StandarEXE. El Servidor esta constituido exclusivamente por clases y sus respectivos métodos y se utilizó una interface para indicar la existencia se esté. 7.3 Descripción del Diseño 7.3.1 Base de Datos De acuerdo a los requerimientos establecidos se hizo el análisis y diseño de base al modelo relacional. A continuación se muestra el Modelo Entidad-Relación que se obtuvo: 73 Cap. 7 Aplicación 7.3.2 Cliente El Cliente maneja las diferentes interfaces gráficas con el usuario (formularios), las cuales le proporciona un manejo de Altas, Bajas, Cambios y Consultas; que puede realizar tanto para los Clientes, Videos y Empleados, así como permitirle realizar Préstamos y Devoluciones de un video. También maneja las interfaces con el Servidor (Objeto COM). Se muestra a continuación un Diagrama de Transición de Estados, en donde se puede observar el funcionamiento del Cliente. Nótese que el Cliente interactua con el Servidor solo cuando hace uso de la Base de Datos. 74 Cap. 7 Aplicación DIAGRAMA DE TRASICIÓN DE ESTADOS DEL CLIENTE [ VIDEO CLUBESPARTACUS MtoClientes MANTENIMIENTO A CLIENTES Pantalla Anterior MtoEmpleados Pantalla Anterior MANTENIMIENTO A EMPLEADOS II ' I MtoVideos > Pantalla Anterior MANTENIMIENTO A VIDEOS PresIDevol Pantalla Anterior I O 1 VIDEO CLUB ESPARTACUS i 1 ALTAS MANTENIMIENTO A CLIENTES J Pantalla Anterior Agregar Registro I InsertBD i L' Pantalla Anterior Baja de Clientes Eliminar Registro I DeleteBD Agregar Cambio I UpdateDB CON SU LTAS Pantalla Anterior ' W Consulta[ Sel. un Cliente ] Consulta Cliente Pantalla Anterior 75 Cap. 7 Aplicación . A VIDEO CLUB ESPARTACUS ALTAS MANTENIMIENTO A EMPLEADOS I ?A i Pantalla Anterior I< Agregar Registro I InsettBD BAJAS Pantalla Anterior Eliminar Registro I DeleteBD Agregar Cambio I UpdateDB CONSULTAS Pantalla Anterior 1 I Consulta[ Sel. un Empleado ] Consulta Empleado Pantalla Anterior VerMenuPrinrjpal NUEVO TITULO ~ AUadeTítulo Panialla Anterior Agregar RegisBoI Insert ~ V P a d l a Anterior ALTAVIDEO i NUEVO EJEMPLAR * EJm@ar Agregar Registro I IIISW~ED Panialla Anterior BAJATITULO i ‘daiadeTítulo i 76 Cap. 7 Aplicación O VIDEO am ESPARTACW 1 VIDEO CLUB ECPARTACUS Pantalla Anterior > > Devolución 77 Cap. 7 Aplicación 7.3.3 Servidor El Servidor maneja la interface con la Base de Datos (llamadas SQL), las cuales la actualizan o consultan, de acuerdo a la petición hecha por el Cliente. También maneja interfaces con el(los) Cliente(s) (instancias), por medio de las diferentes clases de consultas, inserciones, actualizaciones y eliminaciones; enviándole el resultado de cada una de ellas. Se muestra a continuación un Diagrama de Objetos, en donde se puede observar el funcionamiento del Servidor. DIAGRAMAS DE OBJETOS DEL SERVIDOR 1: Selección Opción 2: Mostrar() 1 \ I I rf 3: Captura o Selección de Datos + 4: Aceptar + 5: AtiendePeticiónCliente(DatosCliente) I + I - L__-l I I I ObjCliente I I I IJ 6: InteractuaD B(Datos) El objeto "ObjCliente" cuenta con las sigLlzntes clases, las cuales incluyen sus propios métodos, estos se ejecutan de acuerdo a la petición hecha por el Cliente en el paso 5 del diagrama anterior: ObjCliente ClaseAltaCliente (ClaseAltaCliente.cls) ClaseCambioCliente (ClaseCambioCliente,cls) Clasecvecliente (claseCveClienteaCIS) ClaseEliminarChte (ClaseElinarUiente, cls) ClaseExiste (ClaseExiste.cls) ClaseGetCveCliente(ClaseGetCveCliente,cis) ClaseGetCveCte (ClaseGetCveCteds) 78 Cap. 7 Aplicación 1: Selección Opción 2: Mostrar() 5: At iendePeticiónEmpleado(DatosEmpleado) ObiEmDleado 3: Captura o Selección de Datos --+ + I 4: Aceptar I I$ 6: InteractuaDB(Datos) El objeto "ObjEmpleado" cuenta con las siguientes clases, las cuales incluyen sus propios métodos, estos se ejecutan de acuerdo a la petición hecha por el Cliente en el paso 5 del diagrama anterior: ObjEmpleado ClaseAtaEmpleado (ClaseAltaEmpleado.cls) claseCambioEmpleado (claseCambioEmpleado.cls) ClaseCveEmpleado (ClaseCveEmpleado.cls) ClaseEliminarEMPLEADO(daseEliminarEMPLEAD0,cls) ClaseGetCveEmp (daseGetCveEmp.cls) ClaseGetCveEmpleado(ClaseGetCveEmpleado,CIS) 79 Cap. 7 Aplicación lnteríaz 2: Mostrar() it7-7 5: Envia Petición Video(Datos Video) Video --+- Obivideo El objeto "ObjVideo" cuenta con las siguientes clases, las cuales incluyen sus propios métodos, estos se ejecutan de acuerdo a la petición hecha por el Cliente en el paso 5 del diagrama anterior: ObjVideo ClaseActor (ClaseActords) ClaseAltaActor (ClaseAltaActor .CIS) ClaseCambioTema (ClaseCambioTema.CIS) ClaseCambioTitulo(ClaseCambioTitulo.CIS) ClaseEjemplares (ClaseEjemplar es.cls) ClaseEliminarEjem (ClaseEliminarEjern.cls) ClaseEliminarTkulo (ClaseEliminarTkulo.CIS) ClaseGetCveActor (ClaseGetCveActor.CIS) ClaseGetCveTema (CkeGetCveTema.cls) ClaseGetCveTkulo (ClaseGetCveTkulo.cls) ClaseGetCveTkuloClas(ClaseGetCveTituloCIasLIS) ClaseGetEjem (ClaseGetEjem.cls) ClaseGetFormato(ClaseGetFormato.cls) ClaseNuevaCveActor (ClaseNuevaCveActor.cis) ClaseTerna (ClaseTerna.cls) 80 Cap. 7 Aplicación 1: Selección Opción lnterfaz 5: Envia Petiaón Pkstíüev(Datos P k d D e v ) + I ObiPkU'üev I 3: Captura o S e l e d ó n de Datos II __3 4: Aceptar + 6: InteractuaDB(Dat0s) El objeto "ObjPréstamo/DevoluciÓnll cuenta con las siguientes clases, las cuales incluyen sus propios métodos, estos se ejecutan de acuerdo a la petición hecha por el Cliente en el paso 5 del diagrama anterior: I ObjPrédDev I ClaseDevolucion (ClaseDevolucibn,cls) ClaseGetFolio (ClaseGetFolio,cls) ClasePréstamo (ClasePréstamo,cls) 81 Cap. 7 Aplicación 7.4 Implementación 7.4.1 Creación de la aplicación Cliente. 0 Como ya se había mencionado antes, el Cliente se implementó como un Standard EXE en Visual Basic, así que en la ventana de "New Project'' se seleccionó como sigue: ActiveX DLL VE Enterprise Addin Acthiex Cmbd VE Appkatiwi Wizard ActiveX ActiveX Daurnent DLL Document EXE Se tiene que revisar que se tengan las referencias necesarias (en el menú Project) para la aplicación, ya que sin estas se pueden producir errores cuando se realice la ejecución de la aplicación, en nuestra aplicación serán necesarias las siguientes referencias: 82 Cap. 7 Aplicación Se realizó el diseño con la ayuda del Toolbox, las diferentes interfaces que son necesarias para la aplicación. La primera interface que se muestra, pide el Nombre del Usuario y su Password, ya que con estos datos se realiza una verificación para saber el acceso con el que cuenta el usuario y posteriormente mostrarle otra interface (Principal) con la cual puede hacer uso del sistema, ya que cuenta con las opciones de: Mantenimiento a Clientes, Mantenimiento a Empleados, Mantenimiento a Videos y Préstamo y Devoluciones; dichas interfaces son las siguientes: AI hacer click en Mantenimiento de Clientes o Mantenimiento de Empleados, se desplegará otra interface, en la cual se pueden realizar: Altas, Bajas, Cambios y Consultas sobre la Base de Datos. Cuando se realiza una Alta de Cliente (o Empleado) se muestra una nueva interface, en donde el usuario debe de proporcionar los datos que se le piden y hacer click en el botón de Agregar Registro para que agregue a la Base de Datos. AI realizar una Baja de Cliente (O Empleado) se mostrará una interface, la cual pide la clave del empleado y el Cliente, hacer click en el botón de Eliminar Registro para darlo de baja en la Base de Datos. Dichas interfaces son las que a continuación se muestran: 83 Cap. 7 Aplicación Sí se realiza un Cambio de Cliente (o Empleado) o una Consulta de Cliente (o Empleado), se muestra una interface, en donde se selecciona el cliente y posteriormente otra en la cual se despliegan los datos del cliente, en el caso de realizar un cambio se hace click en el botón de Agregar Cambio para realizarlo en la Base de datos. Se muestran las interfaces: Ai hacer click en Mantenimiento de Videos, se despliega una interface para que el usuario pueda hacer: Altas, Bajas, Cambios y Consultas a los Videos. AI seleccionar Alta de Video, se muestra una interface en donde se piden ciertos datos, ai hacer click en el botón de Agregar Registro, se muestra otra interface en donde se selecciona el Autor, en caso de que el autor que se quiera no exista se tendrá que dar de alta a través del botón Alta Actor y para seleccionar el Tema hacer click en el botón Agregar Tema. Las interfaces descritas son las siguientes: 84 Cap. 7 Aplicación Sí se selecciona Baja de Video, se muestra una interface en donde se elige si la baja será por Título o por Ejemplar, posteriormente se muestra otra interface dependiendo de la elección; en la interface de eliminar por título, se elige este y se hace click en Eliminar Registro para eliminarlo de la Base de Datos; en la interface de eliminar por ejemplar, se debe de elegir tanto el título como la colocación y posteriormente hacer click en Eliminar Registro para eliminarlo de la Base de Datos. Se muestran a continuación dichas interfaces: 85 Cap. 7 Aplicación AI seleccionar Cambios de Video, se muestra una interface en donde se elige el título, posteriormente se muestra otra en donde se pueden realizar cambios tanto al Título como ai Tema y Actor, si se quieren hacer cambios en tema y actor hacer click en el botón CambioTema o CambioActor según se quiera. Una vez hechos los cambios hacer click ai botón Agregar Cambio, para actualizar la Base de Datos. La interface es la siguiente: Si se selecciona Consulta de Video, se muestra una interface en donde se tiene la opción de hacer consultas por: Título, Actor y Tema. AI seleccionar cualquiera de estas se muestra otra interface en donde se elige un título, un actor o un tema según sea el caso; posteriormente se muestran los datos correspondientes a cada uno de estos a través de otra interface. A continuación se muestran estas: 86 Cap. 7 Aplicación AI hacer click en Préstamo/DevoluciÓn se muestra una interface en donde se elige si se quiere hacer una devolución o un préstamo; si se selecciono Préstamo, se muestra otra interface en donde se elige el título, formato y precio, hacer click en Agregarpréstamo por cada préstamo de video que se quiera hacer en la Base de Datos se colocará un status. Si se selecciono Devolución se muestra una interface para elegir el folio de la devolución y posteriormente otra en donde se muestran los préstamos correspondientes a ese folio. AI hacer click en DecoluciónPréstamo en la Base de Datos se quita el status que tiene relacionado el ejemplar. Se muestran las interfaces a continuación: 87 Cap. 7 Aplicación 0 Finalmente se escribió todo el código necesario para que las interfaces se relacionen entre sí y lo que es más importante, la creación del objeto con el cual el Cliente se comunica con el Servidor. En el código que a continuación se muestra: la primer línea se encarga de crear el objeto, la variable Objeto tendrá que ser de tipo Object, el primer parámetro que se encuentra dentro de los paréntesis es el nombre del Servidor al que se va ha conectar y el segundo parámetro es la clase a la que va ha accesar; la sugunda línea ejecuta el procedimiento del objeto (clase), la variable Res deberá ser del mismo tipo del que regresa la función, el primer parámetro es el nombre del objeto que se creó seguido del nombre del procedimiento a ejecutar y si este recibe variables de entrada se escribirán dentro de los paréntesis como sigue: Dim Objeto As Object Set Objeto = CreateObject("Servidor.Clase") Res = Objeto.Procedimiento(Text1,Text2, ... ,Textn) 7.4.2 Creación de la aplicación Servidor 0 Como ya se había mencionado antes, el Servidor se implementó como un ActiveX EXE en Visual Basic, así que en la ventana de "New Project" se seleccionó como sigue: 88 Cap. 7 Aplicación Se tiene que revisar que se tengan las referencias necesarias (en el menú Project) para la aplicación, ya que sin estas se pueden producir errores cuando se realice la ejecución de la aplicación, en nuestra aplicación serán necesarias las siguientes referencias : 0 La aplicación Servidor, solo cuenta con una interface, la cual nos permite tener un control del número de instancias que se conectan con el Servidor. A continuación se muestra dicha interface: ......................... ...................................... ...................................... ...................................... .. ' Base de Datos .. .. . Cliente .. .: .: .. .. I .. .. .. .. .. .. .. . Empleado .. .. ... ... ... ... Video .. .. .. Prestamo .. .. .. .. .. .. . . .. .. .... .... .... .... .... 89 Cap. 7 Aplicación 0 Finalmente se escribió el código necesario para las clases, las cuales accesan la Base de Datos; también el código que bloquea o libera las instancias conectadas al Servidor dependiendo de la petición, las cuales pueden ser: Cliente, Empleado, Video, Préstamo. A continuación se muestra este código: Public Sub BloqueaCliente() If IsNumeric(FrmServidor.Cliente.Caption) Then FrmServidor.Cliente.Caption= "2" Else FrmServidor.Cliente.Caption= "1 End If End Sub I' Public Sub Liberacliente() FrmServidor.Cliente.Caption= End Sub I' 7.4.3 Generación de Setup para la aplicación Cliente-Servidor Remote Automation Ó COM Si la aplicación utiliza un componente ActiveX , el Wizard proporciona un medio para crear setup's tanto para el cliente y como para servidor en un ambiente de Remote Automation Ó COM. A continuación se muestra como creo un setup para una aplicacion Cliente/Servidor y presenta las posibles opciones tanto para un Remote Automation como paraun COM. 7.4.3.1 Creación del setup para el servidor: 1. Inicializar el Setup Wizard. 2. Hacer click en el botón Next para seleccionar la pantalla Select Project and Option. 3. Escoger el nombre del Servidor, tecleando la ruta y el nombre del archivo dentro de la caja de entrada Project File, Ó seleccionar el botón Browse para buscarlo. 90 Cap. 7 Aplicación 4. Seleccionar la opción Create a Setup Program, hacer click en el botón Next para proseguir. Si se desea que el Setup Wizard construya tu proyecto, checar la opción Rebuil the Project. 5. Proseguir hasta la pantalla Shared ActiveX Applications. Seleccionar Install as shared component y Automation Ó No si se desea usar COM. Yes si se desea usar Remote Si se selecciona Remote Automation, los archivos Racmgr32.exe, Racreg32.dl1, Autprx32.dll y Autmgr32.exe serán agregados al setup.lst e instalados con la aplicación servidor en el directorio \Windows\System del servidor remoto. 6. Proseguir hasta crear el setup para el servidor. Esta aplicación servidor se instala en la computadora remota. El setup de esta aplicación instalará los archivos necesarios. 91 Cap. 7 Aplicación 7.4.3.2 Creación del setup para el cliente: 1. Antes de proseguir, asegurarse de que se tiene creado el archivo .vbr para cada servidor remoto que se haga referencia en la aplicación. Crear un archivo .vbr seleccionando la opción Remote Server Component de la caja de diálogo Project Properties en Visual Basic y luego compilar el proyecto. 2. Comenzar el Setup Wizard. 3. Hacer click en el botón Next para seleccionar la pantalla Select Project and Option. 4. Escoger el proyecto servidor tecleando la ruta y el nombre del archivo dentro de la caja de entrada Project File Ó seleccionar el botón Browse para buscarlo. 5. Seleccionar la opción Create a Setup Programa y luego hacer click en el botón Next para proseguir. Si se desea que el Setup Wizard construya el proyecto, checar la opción Rebuil the Project. NÓTESE QUE: Antes de crear el setup para el cliente se deberá de tener compilada la aplicación por lo menos una vez en Visual Basic. 6. Seleccionar la opción distribución y localización, proseguir a la pantalla ActiveX Components. Si el proyecto cliente contiene referencias al servidor local, la aplicación servidor será listada en la caja de archivos. 92 Cap. 7 Aplicación Si se quiere agregar servidores remotos, hacer click en el botón Add Remote. 7. En el prompt solamente se verán los archivos *.vbr de la aplicación servidor. Localizar el archivo en el directorio fuente del proyecto servidor y escoger Open. El archivo .vbr será agregado a una lista de archivos, y aparecerá un diálogo correspondiente Remote Connection Details en donde se escribirá información de la conexión. Si se está usando DCOM, escoger la opción Remote Transport y luego escribir el nombre del servidor remoto en la caja de entrada Network Addresss. Si se está usando Remote Automation, seleccionarlo y luego especificar cualquier dirección de red válida, el protocolo de la red y los niveles de verificación, los cuales se pueden dejar en blanco si se quiere que el cliente Ó el usuario escriba esta información a tiempo de instalación. Seleccionar las opciones apropiadas y hacer click en el botón OK para regresar a la pantalla ActiveX Components. Si tanto la versión local (.exe) y remota (.vbr) aparecen en la lista de los componentes, se debe de eliminar la versión local (.exe). de tal forma que solamente el servidor remoto sea usado por la aplicación cuando sea instalado. 93 Cap. 7 Aplicación 8. Proseguir a través del Setup Wizard para crear el setup cliente . Instalar la aplicación cliente en la máquina del usuario cliente y seguir los procedimientos de Remote Automation o DCOM usando la aplicación cliente-servidor. 94 Conclusiones El vertiginoso desarrollo de los lenguajes de programación ha propiciado la actualización y orientación de sistemas cada vez más complejos, los que por diseño, deberán de cumplir con una serie de requisitos, tales como: 0 El uso del análisis orientado a objetos en el diseño del sistema, el cual reduce en un gran porcentaje el esfuerzo en el desarrollo de la aplicación y proporciona la facilidad de crear una implementación, en la cual se puede representar la interacción de los objetos, en una equivalente a la del mundo real. La portabilidad de los programas debido a la existencia creciente de múltiples plataformas que prevalecen en el mercado. Las interfaces gráficas que hacen que los diseños sean más amigables con los usuarios, acortando la brecha semántica entre la máquina y el ser humano. Es por eso que para la implementación de la aplicación, posteriormente de un análisis y diseño orientado a objetos, se hace indispensable contar con un lenguaje de programación que soporte estos métodos; en Visual Basic ver. 5.0 encontramos el lenguaje que proporciona las ventajas de la metodología y su gran capacidad de crear programas flexibles y modulares, así como la reutilazación de código establecido, haciéndose apropiado para el desarrollo de Sistemas Distribuidos. Como se observa en el diagramas de Transición de Estados y de Objetos, el análisis y diseño orientado a objetos hace que la implementación del sistema se reduzca en gran porcentaje, tanto en código como en esfuerzo, a diferencia que si se hubiese implementado con otra metodología. Los procesos que fueron implementados en esta aplicación son mecanismos que proporciona Visual Basic, el cual permite crear una gran variedad de interfaces gráficas con mucha sencillez. Como se ha mencionado, COM ofrece el protocolo que permite a una aplicación interactuar con otra en la misma máquina, pero dada las necesidades mencionadas anteriormente ahora lo que se busca es la capacidad de comunicar aplicaciones funcionando en máquinas distintas dentro de una red. Esto es esencialmente lo que ofrece DCOM. Este protocolo de comunicación conjuntamente con la creación de objetos permite el desarrollo de Sistemas Distribuidos. 95 Conclusiones El protocolo de comunicación que ofrece DCOM para el desarrollo de Sistemas Distribuidos cubre siguientes funciones: Control de conexión .- DCOM utiliza un contador de referencia para determinar cuántos clientes están conectados a un determinado servidor. Control de flujo Sincronización Control de desconexión .- Cuando el contador de referencia llega a cero, la aplicación se cierra. Cuando un servidor de aplicaciones ya no esté en funcionamiento, DCOM lanzará la aplicación y establecerá el contador de referencia de la manera más adecuada. El gran desarrollo tecnológico que se ha dado sobre las redes de comunicación (la internet), acorta cada vez más las distancias y los tiempos de respuesta. Estos dos grandes factores, motivaron la realización de una Aplicación Cliente/Servidor utilizando el protocolo de comunicación DCOM. Resumen de logros Realmente la parte importante de este proyecto fue el hecho de haber logrado una documentación explícita de lo que se refiere a la metodología COM, es decir, se deja una buena documentación conceptual de lo que es la construcción de los objetos COM. En lo que se refiere a la parte técnica, se logro establecer la comunicación con los objetos COM desde una aplicación normal, ya sea en una misma máquina Ó en máquinas distintas. Por otra parte, la documentación presentada indica que lo mas conveniente para la implementación de un objeto COM es la utilización del lenguaje C, por lo que podemos considerar que esta parte no fue cubierta por el presente proyecto. Sin embargo la implementación de éste se hizo utilizando Visual Basic 5.0 y así mismo la aplicación que utiliza este objeto también fue implementada en la misma herramienta. 96 Conclusiones Propuesta de lmplementaciones Futuras en el Proyecto Manejar aún mas la reutilización de código, específicamente en las clases que maneja el Servidor, para la optimización de tiempo de desarrollo. 0 Distribuir la carga de la aplicación Servidor, es decir, que se tenga un servidor para cada una de las entidades (Cliente, Empleado, Video, Préstamo/Devolución) realizando todas sus operaciones involucradas (Altas, Bajas, Cambios y Consultas). 0 Estos servidores podrían ser codificados en diferentes lenguajes de programación (Delphi, Visual C, Visual Java, etc) y ser accesados por el mismo cliente (sin tener que modificarlo) ya que esto lo soporta DCOM. Agregar nuevas funcionalidades al Sistema de Videos para que su implementación se asemeje al mundo real. Por ejemplo que el sistema maneje Promociones, Proveedores, Finanzas , etc. Codificar los objetos COM en C, en base a los conceptos que se describen en el presente resumen. 97 Bibliografía Berson Alex ClientEerver Architecture McGraw-Hill, 1992 Dwana Travos ClienüServer Computing McGraw-Hill, 1993 Vaughn Larry T. ClienüServer System Design and Implementation McGraw-Hill, 1994 98