Visual Basic 6.0
Nivel Avanzado
–
Incluye:
Clases con Proyectos EXE Standard Standard
Proyectos ActiveX Exe
Proyectos ActiveX DLL
Controles ActiveX (.OCX)
Acceso a la API de Windows
Programación de Sockets
Contenidos Detalles de los Proyectos y de las Clases .....................................................................................................
4
Standard EXE .......................................................................................................................................................
4
ActiveX EXE ..........................................................................................................................................................
5
ActiveX DLL ..........................................................................................................................................................
6
ActiveX Control ...................................................................................................................................................
7
Características generales de la programación orientada a objetos. .................................................... 9
Encapsulación ......................................................................................................................................................
9
Reusabilidad (herencia) .................................................................................................................................
10
Polimorfismo ......................................................................................................................................................
10
Descripción de las clases ....................................................................................................................................
11
¿Qué es una clase o módulo de clase? ....................................................................................................
11
Eventos de un módulo de clase: Initialize y Terminate ..................................................................... 12 Diferencias con los módulos estándar ...................................................................................................... 13 Propiedades y métodos .................................................................................................................................. 13 Propiedades como variables públicas.......................... ........................................ ........................... ........................... ................ 13 Propiedades como procedimientos Property .......................................................................................... 13 Tipos de propiedades Property .......................... ....................................... .......................... ........................... ........................ .......... 14 Métodos ............................................................................................................................................................... 15 Procedimientos vs. Métodos ....................... .................................... ........................... ........................... .......................... ................. .... 15 Alcance de las propiedades y métodos .................................................................................................... 16 Lab01: Diseñando una Clase con propiedades y métodos ....................................................................
17
Creación de objetos y otras consideraciones ..............................................................................................
19
Declarando instancias de clase con CreateObject ............................................................................... 19 Declarando instancias de clase con New ................................................................................................. 19 Declarando instancias de clase que generan eventos ........................................................................ 20 Terminar de usar una instancia de clase ................................................................................................. 20 Conceptos de Late Binding y Early Binding ............................................................................................ 21 Late Binding (Vinculación Tardía) ......................... ...................................... .......................... ........................... ...................... ........ 21 Early Binding (Vinculación Temprana) ............................. .......................................... .......................... ........................ ........... 21 Lab02: Usando la librería creada en Lab01 .................................................................................................
22
Crear y generar eventos en la clases .............................................................................................................
24
Declaración de eventos con la palabra reservada Event ................................................................... 24 Generar un evento declarado con la instrucción RaiseEvent ...................... ...................... ............... 24 Declarar la variable de objeto con WithEvents ..................................................................................... 24 Amigos y Enumeraciones ...................................................................................................................................
25
Compartir información entre clases como amigos: Friend ............................................................... 25 ¿Qué son Enumeraciones? ............................................................................................................................ 25 Cómo declarar y usar las enumeraciones ............................................................................................... 25 Lab03: Añadir Eventos y enumeraciones .....................................................................................................
27
Interfases y polimorfismo ..................................................................................................................................
29
¿Interfases? ........................................................................................................................................................
29
Desarrollando e implementando interfases en VB ............................................................................... 29
Página:2 de 66
Definiendo la interfase. ........................... ........................................ .......................... ........................... ........................... ................... ...... 29 Lab04: Interfases ..................................................................................................................................................
32
Controles de Usuario ............................................................................................................................................
36
Introducción: .....................................................................................................................................................
36
Lab05: Creación de un Control ActiveX (OCX) Paso a Paso .................................................................. 36
Para crear el proyecto ControlDemo ......................................................................................................... 36 Tiempos y vida de un objeto UserControl ............................................................................................... 41 Dibujar el control ShapeLabel .....................................................................................................................
43
Guardar los valores de las propiedades del control ShapeLabel .................................................... 45 Dar una página de propiedades al control ShapeLabel ...................... ...................... ..................... ..... 48 Agregar un evento al control ShapeLabel ............................................................................................... 52 Compilar el componente ControlDemo .................................................................................................... Temas de Programación Avanzada .................................................................................................................
54 56
Acceder a la API de Windows ...................................................................................................................... 56 Comprender la API de Windows ........................... ........................................ .......................... ........................... ...................... ........ 56 Programación Cliente/Servidor en Visual Basic utilizando el Control WinSock ...................... ........ 59
Conceptos Básicos de Programación P rogramación Cliente/Servidor ....................................................................... 59 Comenzando a Programar con el Control Winsock .............................................................................. 61 Protocolos TCP/IP y UDP .......................... ....................................... .......................... ........................... ........................... ................... ...... 61 Propiedades, métodos y eventos de WinSock. ................ ............................. .......................... .......................... ............. 61 Lista de propiedades más importantes: ...................... .................................... ........................... .......................... ............... .. 61 Ejemplo 1 ......................... ....................................... ........................... ........................... ........................... .......................... .......................... ............. 62 Lista de Métodos más importantes ......................... ...................................... ........................... ........................... ................... ...... 62 Lista de Eventos más importantes .................................. ............................................... .......................... ........................ ........... 62 Programando la primera aplicación Cliente/Servidor............................ ........................................ ................... ...... 62 Bibliografía .......................... ....................................... ........................... ........................... .......................... .......................... ........................ ........... 66
Página:3 de 66
Detalles de los Proyectos y de las Clases Algunos de los diferentes proyectos que pueden realizarse dentro del ambiente de desarrollo de Visual Basic 6.0 tiene diferentes características entre ellos y entre las clases que contienen. Veamos detalles teóricos de estas características: Características generales de la ventana de dialogo de Propiedades de Proyecto Standard EXE. ActiveX EXE. ActiveX DLL. ActiveX Control. Los detalles que se verán se observan en el ambiente de Visual Basic 6. Para ver características particulares de un proyecto seleccione Propiedades de NombreDeProyecto... del menú Proyecto. Para ver las propiedades particulares de un módulo de clase vea la ventana de propiedades (F4) para cada módulo de clase. Características generales de la ventana de dialogo de Propiedades de Proyecto
Si observamos la imagen anterior podemos notar dos áreas que en este caso nos interesa recalcar en esta ocasión. El Tipo de Proyecto nos dice el tipo de proyecto que estamos desarrollado en el cual podemos escoger entre Standard Exe, ActiveX Exe, ActiveX Dll y ActiveX Control. Al escoger en cada uno de ellos podemos observar algunas otras propiedades de esta ventana se habilitan y otras se deshabilitan presentando diferentes opciones de configurar el proyecto. El la sección de Modelo de Subprocesos se pueden observar diferentes formas de configuración para el manejo de hilos de ejecución dentro del proyecto dependiendo del tipo de proyecto.
Standard EXE Página:4 de 66
Al tener este tipo de proyecto crearemos una aplicación stand-alone. Si observamos en la imagen anterior podemos ver que no se tiene ningún modelo de hilos de ejecución.Si tenemos un módulo de clase en el proyecto, podemos observar las siguientes propiedades en la ventana de propiedades Devuelve o establece si la clase funcionará como un receptor de datos Devuelve o establece si la clase funcionará como un origen de datos
ActiveX EXE Si seleccionamos que el tipo de proyecto, en la ventana de propiedades del proyecto, sea del tipo ActiveX Exe, el modelo de hilo de ejecución se habilita. (Ver Propiedades de Proyecto)
Subproceso por objeto: informa a VB a crear un nuevo hilo(subproceso) para cada petición de CreateObject de las clases marcadas como MultiUse. Cada hilo tiene una
única copia de todas las variables globales y objetos, y no interfieren con ningún otro hilo. Se recomienda un número pequeño de Clientes/Objetos porque proporciona a cada cliente con un hilo dedicado en el servidor que existe exclusivamente para servir las necesidades de ese cliente. Caso contrario, para una gran cantidad de Clientes/Objetos causa que el servidor consuma una gran cantidad de recursos y causara un rendimiento bajo.
Conjunto de N subprocesos: reduce el número de hilos que consume un proceso
de servidor sencillo. En esta opción se determinan el número máximo de hilos que se crearan para servir a nuevos objetos. Mientras los objetos creados estén bajo este numero esta opción funcionara como Subproceso por objeto, cuando supere la cantidad asignada VB comienza a asignar las peticiones a hilos existentes. Esto significa que varios clientes pueden compartir hilo, lo cual es bueno porque consume menos recursos y malo porque un cliente podría bloquear a otro. Si al cantidad de hilos a crear es igual a uno, entonces coloca el código en modo compatible con VB4 al manejar los objetos a residir en el hilo principal del proceso del servidor ActiveX Exe. Al tener este tipo de proyecto las lista de propiedades para un módulo de clase se vería así: (Ver página siguiente)
Página:5 de 66
La propiedad mas importante de esta lista es la propiedad Instancing, la cual nos indica la forma de crear instancias de la clase fuera del proyecto y si es así como se comportara. Las opciones que se muestran son: 1. Prívate: No se permite el acceso a otras aplicaciones sobre la información de la librería de tipos y no podrá instanciarlo. Estos objetos solo se usan internamente dentro del componente que contiene la clase. 2. PublicNotCreatable: Otras aplicaciones pueden hacer uso de esta clase solo si es creado el objeto primero por el componente que contiene la clase. No se requiere el uso de CreateObject o New debido a que el objeto ya fue creado e inicializado por el componente que lo contiene. Por ejemplo, teniendo referenciado dentro del proyecto el componente de DAO 3.5, podemos utilizar el método OpenDatabase (set dbname = OpenDatabase...) sin tener que utilizar una referencia de un objeto especifico que exponga el DAO tal como lo hace OpenRecordset (Set rsname = dbname.OpenRecordset...) el cual requiere de un objeto tipo DataBase. 3. SingleUse: permite crear objetos de la clase pero cada objeto creado de esta clase crea una nueva instancia de tu componente. No permitido en proyectos de tipo ActiveX DLL. Por ejemplo, en MS Excel por cada instancia a este componente se ejecuta Excel en forma separado (en la barra de tarea tendriamos dos icono para cada instancia). 4. GlobalSingleUse: Igual al anterior, excepto que las propiedades y métodos de la clase pueden ser invocadas como si fueran simples funciones globales. No permitido en proyectos de tipo ActiveX DLL. 5. MultiUse: permite crear objetos de la clase. Una instancia de tu componente proporciona cualquier número de objetos creados de esta manera. Por ejemplo, en versiones anteriores de MS Word para Windows 95 por cada instancia a este componente se ejecuta Word solo una vez (en la barra de tarea tendriamos solo un icono soportando multiple clientes); de la versión de Windows 95, inclusive, a la de Office 97 se comporta como SingleUse, ver arriba. 6. GlobalMultiUse: Igual al anterior, con una añadidura: propiedades y métodos de la clase pueden ser invocados como si fueran simples funciones globales. No es necesario que explícitamente creamos una instancia de la clase porque uno será creado de forma automática. La propiedad DataBindingBehavior permite especificar si la clase funcionará como un receptor de datos. La propiedad Persistable, Establece un valor que determina si un objeto puede guardar y restaurar datos entre varias instancias. Sólo puede establecerse en tiempo de diseño.
ActiveX DLL Si seleccionamos que el tipo de proyecto, en la ventana de propiedades del proyecto, sea del tipo ActiveX Dll , el modelo de hilo de ejecución se habilita de la siguiente forma
Página:6 de 66
Subproceso único: pone el código en modo de compatibilidad con versiones
antiguas y forza a los objetos creados a residir en el hilo principal (STA: Single Threaded Apartment) del proceso del cliente. Si el cliente trata de crear uno de los objetos desde cualquier otro hilo o apartamento, COM automáticamente regresara una representación o agente (proxy) al invocador. Esto asegura que todo acceso al los objetos son serializados hacia el hilo principal. Esto puede impactar el rendimiento debido a que se requieren de dos cambios de hilo para cada llamada a un método. De esta forma VB6 añade la entrada ThreadingModel=Apartment para cada clase que la librería DLL exporta. Esto le indica a COM que se adelante y para crear los objetos dentro del hilo o departamento del invocador, proporcionando que el hilo invocador no se ejecute dentro de un departamento multihilo (MTA: Multithreaded Apartment) en el proceso. Subprocesos
independientes:
Al tener este tipo de proyecto las lista de propiedades para un módulo de clase se vería así:
Con respecto a un proyecto de tipo ActiveX Exe, aquí solo tenemos 4 de las seis opciones para la propiedad de clase Instancing. Estos cuatro son los siguientes: Private: lea arriba en el proyecto de tipo ActiveX Exe para la descripción de esta
opción.
PublicNotCreatable: lea arriba en el proyecto de tipo ActiveX Exe para la
descripción de esta opción.
MultiUse: lea arriba en el proyecto de tipo ActiveX Exe para la descripción de esta
opción.
GlobalMultiUse: lea arriba en el proyecto de tipo ActiveX Exe para la descripción de
esta opción.
ActiveX Control El modelo de hilo de la ventana de propiedades para este tipo de proyecto es igual al tipo de proyecto ActiveX DLL:
Página:7 de 66
Lea en la sección anterior detalles sobre el modelo de subprocesos de un Control ActiveX En este tipo de proyecto se habilita otra opción dentro de la ventana de propiedades del proyecto:
Esta opción habilita el licenciamiento para un proyecto que produce componentes ActiveX (servidores de automatización, controles de usuario o controles ActiveX). Solo se aplica a este tipo de proyecto. Habilitada esta opción, VB creará un archivo de licencia (*.vbl) que deberá ser registrada en la maquina del usuario para los componentes a ser usados en el ambiente de diseño. El programa Aistente para empaquetado y distribución construirá un programa setup que registrara apropiadamente la información en el *.vbl en la maquina del usuario final. Al tener este tipo de proyecto las lista de propiedades para un módulo de clase se vería así:
Con respecto a un proyecto de tipo ActiveX Exe, tenemos las mismas opciones en la propiedad Instancing, para mayor informacion consulte en la sección ActiveX Exe
Página:8 de 66
Características generales de la programación orientada a objetos. Visual Basic tiene su propia manera de implementar la programación orientada a objetos tal como otra muchas cosas dentro de este ambiente. Programadores puros argumentan que Visual Basic no es un lenguaje orientado a objetos, sino a eventos, debido a que no soporta al 100% los tres pilares de este concepto: Encapsulación. Reusabilidad (herencia). Polimorfismo.
Encapsulación Significa simplemente agrupar o contener juntas todas las variables y rutinas relacionadas con el objeto. Permitiendo mantener interno al objeto algunas de estas variables y rutinas y exponiendo otras fuera de él. Muchos de los problemas respecto ha constantes públicas han sido arreglados por el estatuto Enum en la versión 5 de Visual Basic, también puedes establecer una propiedad o método como default y crear colecciones (aunque sigue siendo difícil de codificar). Los procedimientos Property dan a Visual Basic una ventaja sobre C++ y muchos otros lenguajes orientados a objetos en el sentido de que permiten acceso a datos mediante una sintaxis natural y sin exponer datos internos a cambios no autorizados. Pero aún se atrasa respecto a otros lenguajes, en la manera que permite compartir datos entre clases y entre instancias de la misma clase. El nuevo modificador Friend permite compartir datos entre clases permitiendo especificar exactamente lo que quieres compartir con otras clases, pero no permite especificar con quién compartir datos dentro de un proyecto. Visual Basic no proporciona características de lenguaje para compartir datos entre instancias de un objeto (variables estáticas en C++), esto se puede simular con variable públicas dentro de módulos estándar. Los miembros amigos y variable públicas en módulos estándar dentro del proyecto llegan a ser invisibles a los clientes fuera del componente, por lo que hay alguna protección. El gran problema de encapsulación en Visual Basic, es su inhabilidad de inicializar un objeto en su declaración. Este es un gran problema con controles, los cuales contienen Páginas de Propiedades en su mecanismo de inicialización. Porcentaje: 80 % Ejemplo gráfico:
En la dibujo anterior son públicos al programa (el objeto expone) los métodos Abrir, Cerrar, Crear y borrar y las propiedades Color y Contorno. Y son privadas al objeto los
Página:9 de 66
procedimientos Abrir-ventana, Abrir_puerta y la variable Color_puerta. Y cada uno de estos métodos, propiedades, procedimientos y variables están encapsuladas en un objet o. Para ejemplificar las enumeraciones que nos proporciona el estatuto Enum, veamos el dibujo anterior. Podríamos declarar una enumeración global en la que definamos los colores permitidos para la propiedad Color. Esto es, podíamos definir las constantes cteAzul, cteRojo y cteVerde para los colores Azul, Rojo y Verde, respectivamente.
Reusabilidad (herencia) Significa ser capaz de crear una nueva clase que usa características de una clase existente sin recodificar esas características. Significa usar código en una estructura jerárquica. Visual Basic no lo tiene. La manera de obtener Reusabilidad en Visual Basic es a través de un proceso llamado Delegación. Hay dos clases de relaciones de reuso: Relación es-un: Una clase es una versión mejorada de otra clase, definida con herencia. Relación tiene-un: Una clase tiene características de otra clase, definida con delegación. Debido a que Visual Basic no soporta herencia, forza a definir ambos estilos de relaciones con delegación. Modelar una relación es-un usando herencia solo necesitas escribir código para las nuevas características, usando delegación necesitas delegar todo, aún los métodos y propiedades que no cambian. Este proceso mecánico parece ser automatizado, y de hecho, Visual Basic lo automatiza, pero este sólo funciona para controles no para clases. COM soporta una tercera técnica de reuso llamada agregación, significa combinar varios objetos internos de tal manera que parezcan ser parte de un objeto externo. Esta es una organización colectiva en lugar de una organización jerárquica. Visual Basic no soporta esta característica pero algunas ventajas de esta pueden obtenerse con el nuevo estatuto Implements. Porcentaje: 40 % Ejemplo: Una clase llamada ventana (clase base) puede estar contenida en otra clase llamada departamento y en otra llamada cuarto, etc. sin tener que recodificar la clase. La clase o clases que contienen ventana pueden mejorar las características de esta y completarla con la clase que encapsula.
Polimorfismo Significa que cualquier objeto puede ser capaz de hacer lo correcto si recibe un mensaje que entienda. Visual Basic soporta Polimorfismo de dos maneras. Primero, se logra Polimorfismo usando el tipo Object, pero debe evitarse porque es muy lento y no tiene protección de tipo (Late binding) por otro lado, hay ocasiones en la que excesiva protección de tipo se obtiene en el camino y donde la velocidad no es critica. En muchas ocasiones es mejor usar interfaces a través del nuevo estatuto Implements para obtener velocidad. La sintaxis para Implements hace que trabaje al estilo de los eventos. Implements habilita una cantidad de nuevas técnicas. Es casi una implementación directa del poderoso concepto COM de interfaces. Desafortunadamente, algunas de las ventajas de usar interfaces COM se eliminan debido a que Visual Basic no soporta los tipos usados en varias interfaces COM estándar. Página:10 de 66
En muchos lenguajes orientados a objetos, Polimorfismo va mano a mano con herencia. Porcentaje: 70 % Ejemplo: Ambas clases, revista y la clase libro, contienen un método llamado Abrir pero su implementación es diferente respecto una de otra. A pesar que el mismo termino es aplicado a ambos tu sabes la acción correcta a ejecutar
Descripción de las clases Los diferentes proyectos que soporta Visual Basic, de los cuales hemos hablado anteriormente, soportan los módulos de clase con diferentes características de configuración para cada uno de ellos: vea la propiedad Instancing. En esta sección aprenderemos acerca de: ¿Qué es una clase o módulo de clase? Eventos del módulo de clase: Initialize y Terminate. Diferencias con los módulos estándar.
¿Qué es una clase o módulo de clase? Es una plantilla para la creación de objetos.
Es el molde que nos servirá para definir todas las propiedades y métodos, tanto privados como públicos, que deseamos que nuestro objeto final posea. Definirá todas las características que quisieramos que nuestro objeto final tuviera. Por ejemplo: podemos tener una clase llamada clsEmpleados en el cual deseamos tener todas las características con respecto a un empleado. Como propiedades podriamos definir: nombre, apellidos, domicilio, edad, casado, sueldo, fechaIngreso, Antiguedad, etc. Como métodos podriamos tener: ActualizarDatos o GuardarCambios (donde cambios a las propiedades anteriores se grabaran fisicamente en una base de datos), ValidarDatos (donde se valida los datos siempre y cuando haya habido cambios en las propiedades segun una variable privada Cambios). Las propiedades fechaIngreso y Antiguedad son de sólo lectura. Antiguedad se actualiza al instanciar esta clase mediante la función privada Calcula_Antiguedad que contiene la clase, esta función se llama dentro del evento de clase Inicialize. Es parecido a los tipos definidos por el usuario (UDT).
Los tipos definidos por el usuario son agreados de otro tipos, esto es contiene miembros que pueden ser de diferentes tipos (integer, string, etc.), así las clases también concentra diferentes tipos en sus miembros pero la sintaxis es muy diferente. Una clase es un UDT que actua, hace algo. En VB los módulos de clase tiene mayor parecido a las formas o formularios. Por ejemplo: En VB para definir un tipo se logra de la siguiente forma: Type tEmpleado Nombre as string Edad as Integer End Type
Página:11 de 66
Dim Empleado As tEmpleado Empleado.Nombre = "Juan Perez" Empleado.Edad = 25
La variable Empleado se refiere a una instancia de tEmpleado que contiene "Juan Perez" en el miembro Nombre y "25" en el Edad. Cada módulo define un tipo de objeto.
En el momento de instanciar una clase mediante New o CreateObject estamos creando un objeto especifico. Esto es, podemos tener varios módulos de clase para Empleado, Empresa, Venta, ect. y cada uno de ellos define un objeto al momento de instanciar alguno de ellos. En ejecución creas una instacia (o objeto) de la clase.
Los objetos son creados en tiempo de ejecución con los estatutos New o CreateObject. En tiempo de diseño los utilizas los módulos de clase para crear las caracteristicas especificas del objeto. No tiene interfase de usuario.
Los módulos de clase no presentan una interfaz gráfica al desarrollados tal y como lo hacen las formas o formularios. En los formularios puedes colocar visualmente un botón, una lista, un texto, etc. Los módulos de clase solo contiene código que definen las caracteristicas del objeto. Si se desea presentar una ventana informativa (como un Acerca de) u otro formulario, este puede pertenecer a un proyecto ActiveX DLL y mandarlo llamar mediante un método (como MostraAcercaDe) que expone alguna clase dentro del proyecto. Se pueden crear múltiples instacias en ejecución.
De acuerdo a la configuración de las propiedades de la clase se pueden crear varias instancias u objetos de una misma clase. Esto es, la propiedad Instancing de un módulo de clase indica como se trataran los objetos creados utilizando un módulo de clase determinado. Tenemos la opciónde que sea una clase Privada lo cual significa que no se puede instanciar directamente por otro programa, solo el proyecto ActiveX DLL o ActiveX Exe que lo contiene una copia u objeto de este tipo de clase. Proporciona métodos y propiedades.
Algo esencial para definir las caracteristicas y el comportamiento de nuestro objeto a crear con un modulo de clase es definiendo métodos y propiedades a exponer o no.
Eventos de un módulo de clase: Initialize y Terminate Los módulos de clase presenta dos eventos: 1. Initialize: ocurre cuando se crea una instancia de una clase. Se usa, generalmente para inicializar cualquier dato usado por la instancia de una clase en el código. 2. Terminate: ocurre cuando toda referencia a una instancia de una clase son removidas de memoria al establecer todas las variables que la refieren a un objeto a Nothing o cuando la ultima referencia al el objeto se encuentra fuera de alcance. Usado generalmente para limpiar la memoria de objetos creados dentro de esta instancia y generar un error si hay alguna anomalía o guardar alguna información del objeto, etc.
Página:12 de 66
Diferencias con los módulos estándar Deben ser creadas explícitamente (crear i nstancia) antes de usarlas.
No se puede utilizar el método o la propiedad de una clase si no se tiene una instancia de la misma o una referencia al componente que la contiene si la clase esta configurada como Instancing = PublicNoCreatable. Por ejemplo, de la primera forma no podemos utilizar OpenRecordset sin una instancia de un objeto Database; de la segunda forma, no podemos utilizar OpenDatabase sin una referencia al componente que la contiene que es DAO 3.5. Puedes crear múltiples instancias de la clase.
Si las clases están configuradas en la propiedad Instancing como SingleUse, GlobalSingleUse, MultiUse o GlobalMultiUse.
Propiedades y métodos Para poder definir las características del objeto a crear se requieren de tres elementos esenciales: métodos, propiedades y eventos. En esta sección se verán los dos primeros. Propiedades como variables públicas. Propiedades como procedimientos Property. Tipos de propiedades Property. Métodos. Procedimientos vs. Métodos. Alcance de las propiedades y métodos.
Propiedades como variables públicas Las variables declaradas como públicas en módulos de clase se convierten en propiedades de la clase. Ejemplo: Public sNombre As String
Declararlas de esta manera tiene sus limitaciones: No se tiene control sobre la misma: si es de sólo lectura, o de escritura o ambas. Declaradas de esta forma la propiedad es de lectura y escritura. No permite tener una validación previa o ejecutar un procedimiento antes de actualizar la propiedad. No permite generar un error o evento como parte del código de validación o cambio de valor de la propiedad. No permite limitar la propiedad a un grupo de posibles valores. No apareceran en el Object Browser (F2) en versiones anteriores a VB6. No pueden proporcionar ayuda sensible al contexto en versiones anteriores a VB6. Para eliminar estas limitaciones (sobre todo las cuatro primeras en la versión 5 y 6 de Visual Basic) se utilizan los procedimientos Property.
Propiedades como procedimientos Property Utilizando la cláusula Property , para definir las propiedades de la clase, varias de las limitaciones de crear variables públicas se eliminan. Detallemos cómo se eliminan las limitaciones de las propiedades declaradas como variables públicas: Control sobre la propiedad: si es de sólo lectura, o de escritura o ambas.
En procedimientos Property se tienen tres diferentes tipos de procedimientos Property como se vera abajo: Get , Let y Set . Si se declara una propiedad como Get
Página:13 de 66
nada mas, esta es de sólo lectura; si ademas se declara como Let la propiedad se convierte de lectura y escritura. Validación previa, ejecutar un procedimiento antes de actualizar la propiedad y/o generar un error o evento.
Debido a la similitud que existe entre un método o procedimiento con los procedimientos Property , dentro de la declaración de la misma se puede añadir código para realizar una validación, desplegar un mensaje o una ventana de diálogo, generar un evento o un error como parte de la validación o de cambio de valor de la propiedad. Limitar la propiedad a un grupo de posibles valores.
Debido a que se puede tener código, ver arriba, dentro de la definición de la propiedad se pueden tener validaciones en la propiedad Let para validar el valor a asignar a la propiedad o utilizar las enumeraciones para limitar la propiedad a ciertos valores posibles. Uso del Examinador de Objetos (F2) para observar las propiedades y métodos que ofrece la clase.
En versiones anteriores a VB5 las propiedades declaradas como procedimientos Property se observaban dentro de Examinador de Objetos ( Object Browser ) para obtener una referencia rapida sobre una propiedad o metodo. Proporcionar ayuda sensible al contexto, definida dentro del Examinador de Objetos (F2).
En la declaración de la clase, el Navegador de Objetos nos servira entre otras cosas para asignar una pequeña descripción para cada una de las propiedades y métodos que declaremos como publicas dentro de la clase, permitira definir una ayuda de contexto, declarar un metodo o propiedad como default, esconder metodos o propiedades entre otras cosas.
Tipos de propiedades Property Existen tres tipos de procedimientos Property que nos serviran para declarar las propiedades como de solo lectura, solo escritura o de lectura y escritura. Observemos que la definición de una propiedad en VB, mediante procedimientos Property, se parecen en mucho a un procedimiento tradicional al programador, pero trabaja como una variable al usuario del objeto o de la clase. Property Get: lectura, para obtener el valor de una variables de tipo de dato
standard o regresar la referencia a un objeto. Sintaxis:
Property Get NombrePropiedad([ListaArgumentos]) As tipodato 'Código End Property Uso:
Label1.Caption = NombreObjeto.NombrePropiedad Ejemplo:
Private psNombre as String Public Property Get Nombre() as String Nombre = psNombre End Property Property Let: Escritura, para establecer o cambiar el valor de una variables de tipo
de dato standard.
Página:14 de 66
Sintaxis: Property Let NombrePropiedad([ListaArgumentos], NombreValor As tipodato) 'Código End Property
Uso: NombreObjeto.NombrePropiedad = Text1.Text
Ejemplo: Private psNombre as String Public Property Let Nombre(Valor as String) psNombre = Valor End Property Property Set: Escritura, para establecer o cambiar la referencia de una variable de
tipo objeto. Sintaxis:
Property Set NombrePropiedad([ListaArgumentos], Referencia) 'Código End Property
Referencia es, como su nombre indica, un apuntador o referencia de objeto usado en la parte derecha de la asignación de referencias. Uso:
Set nombreobjeto.nombrepropiedad = miobjeto Ejemplo:
Private poEmpleado as clsEmpelado Public Property Set RefEmpleado(ObjEmpleado as clsEmpelado) Set poEmpleado = ObjEmpleado End Property
Métodos Para crear métodos de una clase es muy sencillo lo unico que se necesita es declarar aquellos procedimientos o funciones que se desean compartir como públicos, vea anajo. Al igual que las propiedades apareceran en el Object Browser y mediante este definir una pequeña descripción para cada método expuesto por la clase, además de asignarle un número de contexto de ayuda. Ejemplo: Public Sub Calcula_Costo(Porcentaje As Single) 'Código End Sub Public Function Calcula_Desviacion(Valor as Single) as Boolean 'Código End Function
Procedimientos vs. Métodos
Página:15 de 66
Si hemos observado hasta ahora, las propiedade se parecen a un procedimiento tradicional y los métodos igual observados por el programador, pero para el usuario de la clase o objeto a crear son distintos. Con respecto al uso de las palabra procedimiento y método hay quienes dicen que la dicerencia es el alcance de las mismas dentro de la definición de las mismas dentro de la clases. Esto es, todo aquello procedimientos o funciones que expone la clase al cliente se llaman Métodos, todos aquellos procedimientos que no son expuestos por la clase se llaman Procedimientos. Ahora, observemos que en la programación funcional tradicional se llama a un procedimiento indicando lo que se necesita hacer y se le pasan argumentos para indicar que se quiere hacer: HazEsto AEso, ConEstos
En la programación Orientada a Objetos se indica en lo se quiere trabajar y posteriormente los métodos para indicar lo que se quiere hacer: AEsto.HazEso ConEstos
Alcance de las propiedades y métodos En las definiciones de las propiedades y métodos de una clase, como ya hemos visto en el caso de los métodos, se puede anteponer las siguietes clausulas para limitar o expander su alcance fuera de la clase que los contiene: [Public | Private | Static] [Friend] Property [Get | Let | Set] nombreVar(...
Public: Indica que la propiedad o metodo a definir es accesible a todos los demas procedimientos en todos los módulos. En módulos de clase es lo que se expone a la hora de crear el objeto. Private: Indica que la propiedad o método es accesible solo a otros procedimientos en el módulo donde es declarado. En un módulo de clase, las propiedades creadas con este prefijo solo seran accesible a todos lo miembros (propiedades y metodos, etc.) de este módulo de clase. Static: Friend: Esta prefijo es sólo usado en módulos de clase. Indica que la propiedad o método a definir es visible o accesible a traves del proyecto que la contiene, pero no es visible a un controlador de una instancia de un objeto. Esto es, solo podra ser accesado por ActiveX DLL o EXE que contiene la definición de la(s) clase(s) que contiene un metodo(s) o propiedad(es) con prefijo Friend. El prefijo default es Public. Esto es, si no se especifica el prefijo en la definición de la propiedad o metodo a definir dentro de la clase, este será público. El prefijo default es Public. Esto es, si no se especifica el prefijo en la definición de la propiedad o metodo a definir dentro de la clase, este será público. Ejemplo: Declarar Sub Calcula() es igual a declarar Public Sub Calcula(). Esto puede ser observado en el Object Browser, si se declara de la primera forma en el Navegador de Objetos se vera que se le antepone Public a la definición .
Página:16 de 66
Lab01: Diseñando una Clase con propiedades y métodos Duración: 40 min. aprox Descripción General: Iniciar un proyecto ejemplo: métodos y propiedades
En esta sección de practica empezaremos a definir las primeras propiedades y métodos donde mantengamos las características esenciales de un empleado. En esta practica se requiere de una instancia de Visual Basic. Para guardar sus proyectos, hagalo en su disco duro local creando la siguiente estructura Disco Duro (C:)
VBAvanzado
PracticaGuiada01
Dentro de la carpeta VBAvanzado deberá crear UNA CARPETA por cada Proyecto que realicemos. DESCRIPCION DE PASOS A EJECUTAR
1. Ejecute Visual Basic 6. 2. En la ventana de dialogo que aparece, seleccione un nuevo proyecto de ActiveX DLL . Esto creara un nuevo proyecto de tipo ActiveX DLL dentro del cual ya presenta un módulo de clase lista para llenarse. 3. Ahora, seleccione Agregar Proyecto del menú Archivo y seleccione un proyecto de tipo Standard Exe . Esto añadirá un nuevo proyecto a nuestro grupo de trabajo, en este caso de tipo Standard Exe dentro del cual ya presenta una forma o formulario listo para llenarse. 4. Es el momento de salvar nuestro proyectos y grupo de proyectos. Al módulo de clase llámelo clsEmpleado.cls, al proyecto de ActiveX DLL llámelo stdLib32.vbp, a la forma llámelo CatEmpleado.frm al proyecto de Standard Exe llámelo SysEmp.vbp y finalmente al grupo de proyectos llámelo Curso.vbg. De aquí en adelante guarde sus proyectos en tiempos razonables para impedir perdidas de información por alguna falla de luz o accidente. 5. De igual forma vamos a nombrar a los módulos de nuestros proyectos. Seleccione, del Project Explorer (Ctrl-R) seleccione a Project1 (stdLib32.vbp) y de la ventana de propiedades (F4) cambie su nombre a stdLib32 en la propiedad Name. De igual forma seleccionemos Class1 (clsEmpleado.cls), Project2 (SysEmp.vbp) y Form1 (CatEmpleado.frm) y nombrémosle, respectivamente, clsEmpleado, SysEmp y frmCatEmpleado. 6. Observe las propiedades del módulo de clase. Deseamos que esta clase pueda ser instanciada las veces que se quiera y a petición del cliente. ¿Cómo lo declarará? Observe la sección ActiveX Exe las opciones para la propiedad Instancing.
Página:17 de 66
En el módulo de clase declare las siguientes propiedades cómo públicas (L: Lectura; E:Escritura): Nombre: Cadena (L/E) Apellidos: Cadena (L/E) Edad: Entero (L/E) Sexo: integer (L/E); 0: Femenino, otro: Masculino FechaIngreso: Fecha (L/E) Antiguedad: Integer (L) Sueldo: Moneda (L) También declare los siguientes métodos: Aumentar_Sueldo: en el que se recibe como argumento el porcentaje a aumentar y regresan True si fue posible actualizar el sueldo o no. Se aumenta si el sueldo actual es mayor o igual a 1000 (mil). Disminuir_Sueldo: en el que se recibe como argumento el porcentaje a disminuir y regresan True si fue posible actualizar el sueldo o no. Se disminuye si el sueldo es mayor a 0 (cero). Además de declarar estos métodos y propiedades, codifiquelos. Para las propiedades basese en lo que se vió en Tipos de propiedades. También al momento que sea inicializado la clase para crear un objeto, inicialice el sueldo a 1000 (mil) pesos y la fecha de ingreso a la actual del sistema en el evento Initialize de la clase, como se vio en Eventos de un módulo de clase. En esta practica es todo lo que se va a diseñar. Guarde su proyecto o grupo de proyectos. Quizás este sea el momento para resolver algunas dudas con el instructor o continuar, si aun dispone de tiempo, en Visual Basic para observar algunas otras caracterí sticas o funciones. Por ejemplo, puede observar el Examinador de Objetos (F2) para ver si es posible ver la clase que generó en el proyecto y ver los metodos y propiedades que a creado y si estas son de lectura/escritura o de sólo lectura. Si no lo a probado, en este momento puede checar los características para cada proyecto y las clases. Esta práctica debe desarrollarse conjuntamente con el Instructor
Página:18 de 66
Creación de objetos y otras consideraciones En esta sección se enfoca en la creación de los objetos o instanciación de las clases y otras consideraciones a tomar en cuenta en cuanto el manejo de los proyectos ActiveX Exe o Dll para el proceso de depuración. Declarando instancias de clase con CreateObject. Declarando instancias de clase. Declarando instancias de clase que generan eventos. Terminar de usar una instancia de clase. Conceptos de Late Binding y Early Binding.
Declarando instancias de clase con CreateObject Requieres de crear en tiempo de ejecución la conexión a la clase mediante CreateObject debido a que no se conoce el nombre de la clase o aun si se conociera no se puede utilizar en VB en tiempo de diseño sin una libreria de tipo (type library). Para esto, necesitas conocer la cadena ProgID proporcionada por el proveedor. ProgID consiste en el nombre del sservidor de la aplicación seguido por un punto y el nombre de la clase. Para realizar la declaración e instanciación se requiere de una variable de tipo Object y utilizar la instrucción CreateObject como sigue: Dim nombreVar As Object set nombreVar = CreateObject(ProgID)
Por ejemplo: En versiones anteriores a la 95 de Office, esto es lo que se tenia que hacer para lograr una comunicación OLE con Word. Dim appWord As Object Set appWord = CreateObject("Word.WordBasic")
Declarando instancias de clase con New Las instacia de clase son llamadas usualmente Objetos. Para declarar una instacia de clase se debera utilizar una variable del tipo de la clase que deseamos instanciar y utilizar la clausula New para generar la instacia u objeto. Dim Empleado as clsEmpleado Set Empleado = New clsEmpleado
La razón de usar New es porque con las instancias de clase, la variable no es lo mismo que la instancia. La variable es el único medio de comunicación con la instancia. Las variables de clase con también llamados variables de objeto y las instancias son llamados Objetos. Existen dos formas de instanciar las variables de objeto mediante la clausula New: Declarar la variable de objeto y posteriormente utilizar Set... New para instanciar la clase. Un ejemplo de este caso es como se manejo arriba. Dim VariableObjeto As NombreClase Set VariableObjeto = New NombreClase
Página:19 de 66
Esta es la forma más recomendablesi se desea tener el control sobre la instancia de la variable: cuando debo crearlo, usarlo, terminarlo, volverlo a crear... etc. Instanciar la variable de objeto en la misma declaración de ésta como As New. Dim VariableObjeto As New NombreClase De esta forma a la hora que entre al modulo o procedimiento que la contiene se generara automáticamente la instanciación de la clase. Se tiene menos control sobre la instanciación de la clase; estos sin poder determinar el momento en que deseamos que nuestra variable de objeto se instanciado. Podermos terminar la instanciación utilizando Set... = Nothing. Se recomienda el uso de esta solo para variables de objeto temporales dentro de un procedimiento o función, pero para uso mas confiable o tener mayor control sobre en que momento deseo instanciar mi clase es mejor de la primera forma.
Declarando instancias de clase que generan eventos Si la clase que se va a instanciar genera eventos y se desea atrapar estos eventos para codificarlo, entonces declare la variable de objeto insertando WithEvent entre la clausula Dim y el nombre de la variable: Dim WithEvents Empleado As [New] clsEmpleado
Para atrapar el evento o eventos que genera la clase a instanciar escriba un procedimiento que se llame segun el nombre de la variable de objeto y el nombre del evento a atrapar insertando entre los dos un caracter underscore ('_'). Private Sub Empleado_Cambio([listaArgumentos]) 'Código del evento End Sub
Si observa lo anterior se ve el parecido con los eventos de cualquier control, solo que aqui hay que codificarlo y en el caso de los controles el ambiente de Visual Basic te los presenta en una lista. Se puede observar con el Objet Browser las propiedades, metodos y eventos que la clase esta exportando.
Terminar de usar una instancia de clase Para terminar una instancia de clase o objeto, independientemente de como haya declarado la variable de objeto, es muy sencillo. Solo deberá establecer la variable de objeto a Nothing. Esto generará que el evento Terminate se genere dentro de la clase que estamos instanciando con la variable de objeto.
Set Empleado = Nothing
Posterior a esto y de acuerdo a alguna otra acción o vento del usuario se puede volver a instanciar esta variable de objeto mediante Set.. New (vea arriba).
Página:20 de 66
Se recomienda terminar el objeto si ya no se esta usando para poder liberar recursos del sistema, además de asegurarse de que se esta liberando recursos al momento de salir, por ejemplo, si un procedimiento contiene la declaración y uso de la variable de objeto (se supone que al perderse el alcance de cualquier variable se termina su uso) puede asegurarse que realmente se termine este objeto.
Conceptos de Late Binding y Early Binding Late Binding (Vinculación Tardía) Significa que la variable de objeto es conectado a la clase en tiempo de ejecución. Esto es malo. Debido a que no se tiene una libreria de clase se tiene que utilizar este método. Se utiliza la instrucción CreateObject para lograr la conección a la clase. Cuando, en código y despues de lograr la conección a la clase, haces referencia a un método con argumentos VB requiere de buscar el método por nombre en la tabla de datos de la clase y requiere de pasar los argumentos en tipo Variant (siendo o no los parámetro de tipo Variant) y hacer otras varias cosas que consumen tiempo para obtener todo lo necesario. Lo cual hace más lenta la comunicación con el servidor. VB utiliza una interface COM llamada IDispatch para realizar realizar todo lo anterior. Lo anterior no significa que IDispatch sea malo en general. Este se requiere para VBScript y otros ambientes que siempre realizan late binding.
Early Binding (Vinculación Temprana) Significa que la variable de objeto se conecta a la clase en tiempo de compilación mediante una librería de clase. Esto es bueno. Se utiliza New para lograr la conexión a la clase. La librería de tipo utilizada para la conección a la clase se referencia con la vantana de dialogo que aparece al seleccionar References en el menú Project de VB. Cuando la aplicación es compilada, VB busca, en su librerias de clase activas, las referencias hechas en código. La librería de clase es esencialmente una tabla con offsets a las direcciones de cada propiedad y método. Por eso es llamado vtable (Tabla virtual). Esto hace más rapida la conexión y la comunicación con el servidor ActiveX.
Página:21 de 66
Lab02: Usando la librería creada en Lab01 Proyecto ejemplo: uso de nuestra librería
Ahora empezaremos a usar la librería declarará en la primera parctica en el proyeto de tipo Standard Exe que tambien fue definido. Si no tiene abierto el grupo de proyecto que se guardó en la practica anterior, es tiempo de abrirla en este momento. Recuerde que el grupo de proyecto se encargará de cargar ambos proyectos grabados en la primera practica. En esta sección trabajaremos en el proyecto Standard Exe definido anteriormente. Primero necesitamos realizar la referencia a nuestra libreria dll diseñada en la sección anterior. Recuerde que teniendo abierto ambos proyectos, VB en tiempo de diseño registra el servidor dll en windows por lo que lo podra referenciar. Abra la ventana de referencias (Referencias del menu Proyecto) y seleccione nuestra librería. Esta debe llamarse Stdlib32 en la ventana de dialogo que aparece (a menos que se haya dado una descripción de proyecto en las propiedades del proyecto ActiveX Dll para Stdlib.dll ), si fue asi entonces esta pequeña descripción aparecerá en la ventana de dialogo References. Seleccionela y salga de esta ventana. Una vez referenciada nuestra librería (acuerdese que esta referencia utiliza una libreria de tipo) podemos utilizar las clases que expone. Como la unica clase que tenemos es de tipo MultiUse, necesitamos generar un objeto como se vio en la seccion anterior. En la sección de declaraciones de forma o formulario que se tiene para el proyecto Standard exe, declare una variable privada de objeto de tipo CEmpleado. Declarelo sin la clausula New para poder definir nosotros el momento en que deseamo inicializar esta variable. Observara que en el momento de teclear As más el espacio, VB5 le presenta una lista flotante para poder seleccionar el tipo y mientras escribe las primeras letras del tipo tratara de adivinarlo. Puede moverse a traves de esta lista utilizando las flechas y avance/retrocesode paginas, una vez ubicado sobre el tipo a seleccionar presione TAB (arriba de la activación de mayusculas, lado izquierdo). Esta situación se presentará en varias otras ocaciones, utilicelo para agilizar el código. En este caso vamos a utilizar el evento Initialize del formulario para inicializar nuestro objeto. (Tambien puede usarse el evento Load del Formulario) Vaya al evento Initialize y escriba el código necesario para inicializar nuestro objeto de tipo CEmpleado. Ahora vamos a colocar en nuestra forma o formulario los siguientes controles: Necesitamos de los correspondientes Labels y TextBox para cada una de las propiedades de nuestro objeto de empleado. Insertelas en forma vertical para: Nombre, Apellidos, Edad, Sexo, FechaIngreso, Antiguedad y Sueldo. Estas dos ultimas son de solo lectura por lo que deberá de colocar la propiedad Locked como True para que no sea modificable. A estos controles escribales un nombre segun el dato que mantendra. Ahora colocaremos en la parte inferior los siguientes botones: Añadir, Borrar, Aumentar Sueldo, Disminuir Sueldo y Salir. Antes de meternos a codificar los botones, generemos un procedimiento privado dentro del formulario que se llame Actualizar_Forma. Inicialice dentro de este procedimiento cada uno de los controles TextBox con los valores actuales del objeto empleado. Recuerde lo siguiente para codificar este procedimiento: La fecha de ingreso tiene el siguiente formato a desplegar: dd/mm/yyyy. Y en sueldo solo muestre dos digitos en los decimales y el signo de pesos al inicio.
Página:22 de 66
Por lo pronto mande llamar a este procedimiento en el evento Load de la forma para que refresque los datos al entrar al sistema. Ahora añadamos el codigo necesario para los botones. Añadir : codifique este botón para igualar los datos actuales de los textbox al objeto creado. Puede utilizar validación de datos si lo desea. Borrar : de lo que se trata es que el objeto del empleado actual deberá borrarse y crearse uno nuevo. Debera actualizar la forma al nuevo objeto. Aumentar : mendiante una caja de entrada (instrucción InputBox) obtener un valor entero entre 1 y 100, para poder aumentar el sueldo al empleado actual. Aumentele el sueldo al empleado y despues actualice la forma para actualizar esta información en pantalla. Disminuir : igual que la anterior, pero se trata ahora de disminuir el sueldo. Salir : para salir de la aplicación o de la forma. Pruebelo. Ejecute la aplicación (F5) para ver nuestro objeto de empleado funcionando. Nota: Este Lab es guiado por el instructor.
Página:23 de 66
Crear y generar eventos en la clases En esta sección veremos como crear un evento o una serie de eventos en una clase y, de acuerdo a alguna acción, generar un evento para avisar al usuario de la clase. Generar eventos en muy sencillo en VB5 y VB6 (en VB4 no se puede), solo siga las siguientes indicaciones: Declaración de eventos con el estatuto Event. Generar un evento declarado con la instrucción RaiseEvent. Declarar la variable de objeto con WithEvents .
Declaración de eventos con la palabra reservada Event La sintaxis para declarar es muy sencilla. En la sección de declaraciones de un módulo de clase declare el o los eventos a generar en algun método o propiedad de la siguiente forma: Event nombreEvento([listaArgumentos])
Generar un evento declarado con la instrucción RaiseEvent Para generar algún o algunos de los eventos declarados se utiliza la instrucción RaiseEvent dentro de algun procedimiento, método o propiedad que requiera para notificar al cliente de la clase que algo a ocurrido. La sintaxis para generar el eventos es: RaiseEvent nombreEvento([listaArgumentos])
Declarar la variable de objeto con WithEvents Esto ya se vió anteriormente, si no recuerda como declarar una variable de objeto con una clase vaya a instancias de una clase con eventos. En aquella sección se vio la declaración de la variable de objeto insertando WithEvents entre el estatuto Dim y el nombre de la variable objeto. Y para atrapar y codificar los eventos se utiliza un procedimiento con el nombre de la variable de objeto, underscore y el nombre del evento a atrapar con los argumentos ar gumentos a recibir.
Página:24 de 66
Amigos y Enumeraciones Enumeraciones La mejor forma de implementar Programación Orientada a Objetos es con 2 o mas clases cooperando entre sí. Las clases necesitan compartir información pero no con otras clases. En sección veremos como VB5 comparte información entre clases del mismo componente. Además veremos para que nos sirven las enumeraciones y como definirlas y usarlas. Compartir información entre clases como amigos: Friend. ¿Qué son enumeraciones? Cómo declarar y usar las enumeraciones.
Compartir información entre clases como amigos: Friend Muchos lenguajes de Programación Orientada a Objetos proporcionan un modificador Friend para permitir que las clases compartan información entre ellos permitiendo especificar quienes son tus amigos. La interpretación de Friend de VB6 es muy pobre, te permite decir que tienes amigos y cualquiera dentro del componente es tu amigo y nadie te t e conoce. Esto es, en VB6 tu declaras tus métodos y propiedades como Amigos y todos dentro del componente que lo contiene (ActiveX Exe o ActiveX Dll) puede verlos y usarlos y cualquiera fuera del componente no pude utilizarlos. La sintaxis para declarar propiedades o métodos incluyen este modificador como opcional: [Public | Private | Static] [Friend] Property [Get | Let | Set] nombreVar(...
De Public, Private y Static se vio información en alcances de los metodos y propiedades.
¿Qué son Enumeraciones? Las enumeraciones son un grupo de constantes definidas que pueden describir entre otras cosas posibles valores de retorno para una función especifica o evento generado por la clase. Tambien pueden ser posibles valores disponibles para algun argumento de entrada a algún método o propiedad de la clase. Por ejemplo, supongase que tenemos una propiedad llamada Color y en la cual se desea que los únicos valores válidos son Azul, Rojo y Verde al momento que se le asigne un valor. Podriamos definir las constantes públicas 1 para Azul, 2 para Rojo y 3 para verdes o definir las enumeracines con esas mismas co nstantes.
Cómo declarar y usar las enumeraciones La sintaxis para declarar una enumeración es parecida a la declaración de tipo definidos por el usuario UDT: [Public | Private] Enum nombreEnumeración nombreMiembro [= constante_o_Expresión] End Enum Si el nombreMiembro no se iguala a una constante o expresión iran tomando los valores
secuenciales, segun su orden de definición (de arriba a abajo), los valores 0, 1, 2, 3, 4,...
Página:25 de 66
El default, como ya se dijo en métodos y propiedades, es Public. Si se declara como tal los usuarios de la clase podran usarlo, lo cual es recomendable si va a regresar o recibir un valor de este tipo. Si solo es de uso interno en la clase entonces declararlo como Private. Por ejemplo: para nuestro ejemplo anterior podriamos definir nuestro grupo de colores como sigue: Enum icColores Azul = 10 Rojo = 15 Verde = 20 End Enum
Una enumeración puedes utilizarlo para definir una variable de este tipo y si puedes definir una variable cuyos posibles valores estan limitados a los valores que la enumeración contiene tambien puedes definir parametros. Ejemplos: Dim A as icColores Property Get Color() As icColores 'Valores validos a regresar son los contenidos en icColores End Property
Property Let Color(Valor as icColores) 'Valores validos a asignar son los contenidos en icColores End Property
En asignaciones recuerdese que las enumeraciones son como variables globales y se puede utilizar o su valor numerico o el nombre declarado en la enumeración. Ejemplos: A = 10 es equivalente equivalente a escribir A = Azul A = varobj.Color varobj.Color varobj.Color varobj.Color = 20 es equivalente a varobj.Color = Rojo
Página:26 de 66
Lab03: Añadir Eventos y enumeraciones Proyecto ejemplo: añadir eventos y enumeraciones
Ya hemos aprendido como crear metodos y propiedades a un modulo de clase y crear nuestros objetos en base a una clase compartida. Es momento de practicar nuestras dos ultimas sesiones en la cual abarcamos los temas de eventos, enumeraciones y Amigos. Veremos por lo pronto la implementación de los dos primeros en esta sesión de practica. En esta sección seguiremos trabajando en el proyecto ActiveX Dll y Standar Exe definidos en los Labs anteriores. Definamos una enumeración en StdLib32.dll . Como ya vimos, en secciones anteriores, las enumeraciones nos pueden servir, entre otras cosas, a limitar los posibles valores para una propiedad. En nuestro proyecto ejemplo, el mejor candidato a esto es la propiedad Sexo. Este debe tomar o regresar solamente dos valores: Masculino o Femenino. Segun la sintaxis que se vio en Amigos y enumeraciones, definir una constante para Masculino y otra para Femenino en la sección de declaraciones de la clase. Realicemos los cambio necesarios para que el valor de la propiedad sexo esté limitado a la enumeración. Tenemos que definir las propiedades Get y Let de Sexo como de tipo enumeración, además de la variable privada que contiene el valor de esta propiedad. Ademas en el evento de Initialize de la clase inicialice la propiedad de sexo al valor que desee (vera que al poner el signo de asignación aparecerá una lista flotante indicandole los posibles valores, eliga uno con las flechas y TAB). Una vez realizados estos cambio presione F2 para ver el Object Browser como me coloco un nuevo elemento del lado izquierdo con un icono distinto a la de la clase, esta es la enumeración que definimos. Realice los cambios necesarios en SysEmp.exe. Ahora en lugar de utilizar un textbox para mostrar el valor que se obtiene de la propiedad Sexo del objeto empleado, defina dos OptionButton con leyenda igual a Mascullino y Femenino, respectivamente. Y en el código de el botón Añadir deberá realizar un cambio en base al OptionButton seleccionado igualar la propiedad Sexo con la constante adecuada. Además el procedimiento Actualiza_Forma debera contemplar el valor obtenido de la propiedad Sexo para habilitar un OptionButton. Pruebelo. Presione F5 para ejecutar la aplicación y probar. Ahora definamos un evento en el módulo de clase CEmpleado. Para nuestro caso vamos a definir un evento en que nos indique del cambio de sueldo del empleado. Primeramente vamos a definir otra enumeración con dos posibles valores: AumentoSueldo y DisminuyoSueldo. Ahora como se vió en Eventos en las clases , declare un evento llamado CambiosSueldo el cual envíe como parámetro si el sueldo aumento o disminuyo, segun la enumeración recien creada. Enseguida coloque en los metodos, como se vio en Eventos en las clases la generación del evento, el cual lo recibirá el usuario. Observe el Examinador de Objetos ahora tenemos dos nuevos miembros: la enumeración (ado izquierdo) y el evento (lado derecho al seleccionar la clase que la contiene). Ahora hagamos los cambios necesario en SysEmp.exe para atrapar los eventos generados por la clase.
Página:27 de 66
Recuerda como se vió en Eventos en las clases , para declarar nuestras variables de objeto para que intercepte los eventos. Bueno, pues vaya a la sección de declaraciones del formulario y haga los cambios pertinentes. Ahora defina el procedimiento de evento para atraparlo. Como parte del código dentro del evento, segun el parámetro recibido, despliega un mensaje que diga: Se aumento el sueldo o en caso distinto Se disminuyo el sueldo . Pruebelo. Presione F5 para ejecutar la aplicación. Recuerde de salvar su grupo de proyecto.
Página:28 de 66
Interfases y polimorfismo VB presenta una nueva característica muy poderosa para la implementación de interfases. En esta sección describiremos que son las interfases y como se implementan en VB5. ¿Interfases? Desarrollando e implementando interfaces en VB6.
¿Interfases? Interfases es el concepto de moda en diseño del lenguaje. Cuando Java incorporó interfaces como una característica del lenguaje se proclamo que las interfaces son el mejor sustituto para el concepto más maligno de herencia múltiple. En VB6 la nueva cláusula Implements proporciona esencialmente esta misma característica (Delphi también incorpora algo similar). Además se parece mucho la sintaxis de eventos y requiere definir variables objetos extras en ciertas situaciones. El propósito principal de Implements no es herencia múltiple sino polimorfismo. Supongamos que se tiene dos clases donde una parte del código es genérico para ambas y otra parte es muy específica a cada clase. En estos casos se escribe una interfase para la parte genérica y las dos clases implementan la interfase para la parte específica. La parte genérica utiliza los objetos con implementaciones especificas sin conocer o preocuparse lo que esos objetos hacen o como lo hacen. Las interfaces encapsulan clases de la misma forma que las clases encapsulan miembros y métodos. Y tal como una clase esconde el estado interno de sus objetos, una interfase esconde la implementación de sus clases.
Desarrollando e implementando interfases en VB Definiendo la interfase. Para crear interfaces en VB simplemente añade un módulo de clase con los métodos y propiedades vacias, o sea, sin codigo; recuerdese que la implementación (el código) de estos es particular para cada clase que lo implementa. Por ejemplo: En un módulo de clase se definen las siguientes caracteristicas: Property Get Nombre() As String End Property Property Let Nombre(Valor As String) End Property Function Aumentar_Sueldo() as Boolean Ends Function
Una interfase no tiene código porque no hacen nada, deberá crear al menos una clase por separado que implemente la interfase, ponerle código. En VB, como para las variables, se utiliza un prefijo para darle un nombre al módulo de clase: para las clases se utiliza 'C', para las interfases 'I'. Se podria tener una clase llamada CEmpleado la cual implementa una interfase llamada IPropEmpleado. Implementando una Interface.
Página:29 de 66
La cláusula principal en la implementación de interface es Implements. La sintaxis para realizar una implementación de una interface es (se coloca en un módulo (o modulos) de clase diferente a la interface que se va a implementar): Implements nombreInterface
Esta instrucción se coloca en otro módulo de clase diferente al modulo que definio la interfase. Esto es porque esta nueva clase hará la implementación de la interfase (le pondrá codigo a la interfase). Lo interesante acerca de este estatuto es lo que realiza con la ventana de codigo que lo contiene. La lista de objeto presenta una nueva entrada para la interface a implementar. Haga de cuenta que insertó un control y desea introducir codigo en sus eventos. De esta misma forma en la ventana de código puede elegir la interface y moverse a través de los miembros a implementar por medio de las listas superiores de la ventana de código. Los procedimientos de interface se parecen a procedimientos de eventos poque como tales no puden cambiarse el nombre y no pueden ser ignorados. Si ignora implementar alguno de estos miembros VB5 le reclamará con un error en tiempo de compilación. Posiblemente algunas de las propiedades de la interface a implementar deberan ser publicas mediante otro procedimiento Property . Por ejemplo: supongamos que deseamos implementar IPropEmpleado: Implements IpropEmpleado Private Property IpropEmpleado_Get Nombre() As String 'codigo End Property Private Property Let IpropEmpleado_Nombre(Valor As String) 'codigo End Property Private Function Aumentar_Sueldo() 'código End Function
Para implementar una propiedad pública que tenga acceso a la propiedad imprementada Nombre por ejemplo: Public Property Get Nombre() As String Nombre = IpropEmpleado_Nombre End Property Public Property Let Nombre(Valor as string) IpropEmpleado_Nombre = Valor End Property
No podemos poner la implementación de nombre como pública porque el nombre de la propiedad a exponer sería IpropEmpleado_Nombre en lugar de algo que lo defina bien: Nombre. Usando una interfase en procedimientos genéricos. Podemos implementar un procedimiento genérico en un módulo estandar del proyecto que utiliza la clase que en base a una interface realice alguna acción.
Por ejemplo: vamos a ejemplificar lo anterior para que se entienda. Ya realizamos nuestra interface de IPropEmpleado ahora deseamos utilizar esta interface en un procedimiento generico que lo unico que va a hacer es imprimir el nombre y sueldo en una caja de dialogo.
Página:30 de 66
Este código puede estar en un módulo estandar para que se pueda accesar desde cualquier parte del proyecto. Sub ImprimePropEmpleado(propEmp as IPropEmpleado) MsgBox "Nombre empleado: " & propEmp.Nombre & vbCrLf & "Sueldo actual: " _ & propEmp.Sueldo End Sub
El objeto que pases como parámetro a este procedimiento deberá implementar la interfase IPropEmpleado. De esta forma suponga que tiene dos implementaciones distintas de IPropEmpleado: CEmpleadoGeneral y CEmpleadoEspecial. Si se definen dentro del evento Click de un botón en una forma el siguiente código se observaran los nombre y sueldos de las personas definidas por las dos variables. una tras de otra en una ventana de dialogo. Private EmpGen As New CEmpleadoGeneral Private EmpEsp As New CEmpleadoEspecial EmpGen.Nombre = "Juan Perez" EmpEsp.Nombre = "Miriam Hernandez" ... ImprimePropEmpleado EmpGen ImprimePropEmpleado EmpEsp
Si observa las dos ultimas líneas, el procedimiento ImprimePropEmpleado recibirá solo la implementada de la interfase IPropEmpleado. VB6 puede implementar las llamadas de interfaces en tiempo de compilación.
Página:31 de 66
Lab04: Interfases Olvidémonos por lo pronto de lo que hemos diseñado para la clase CEmpleado. En los siguientes puntos a desarrollar nos basaremos en el codigo generado en la clase; esto es, en donde se requiera solo realice Copiar de código que ya se tiene y Pegar a los nuevos módulos de clases que se van a añadir al proyecto de ActiveX DLL. Siga estos puntos paso por paso, no se salte ninguno sin haber ternimado por completo estos, si tiene duda o no sabe como pregunte al instructor para poder seguir avanzando. Vamos a trabajar en los siguientes puntos en el proyecto de ActiveX DLL: Vamos a diseñar la interfase que presente algunas caracteríticas genericas para dos clases nuevas que diseñaremos: CAgente y CDirectivo. En el primer paso diseñaremos la interfase y en las siguientes las dos clases y algunas funciones genéricas para ambas. Para este ejemplo, no crearemos ni enumeraciones, ni eventos, ni amigos... sólo lo indicado. Insertemos un nuevo módulo de clase en nuestro proyecto de libreria DLL. Esta clase sera nuestra interfase por lo que la llamaremos IEmpleado. Definamos la interfase con las siguientes propiedades (acuerdese que en las interfaces solo se definen sin ponerles código ni relacionandolas con variables privadas. Solo declare los procedimientos Property ): Nombre: Cadena (L/E) Edad : Entero (L/E) Sueldo: Moneda (L) Y declare los siguientes métodos (solo declarelos no los implemente): AumentaSueldo: recibe como parámetro el porcentaje a aumentar. DisminuyeSueldo: recibe como parámetro el porcentaje a disminuir.
Por lo pronto, asi de sencilla sera nuestra interfase. Ahora agrege dos módulo de clase y llamelos CAgente y CDirectivo. Mencionele a VB que se desea implementar la interfase IEmpleado en ambos módulos de clases. Como se vió en Interfase y Polomorfismo. Observe en la lista superior izquierda de los módulos donde realizo la referencia a implementar la interfase, busque el nombre de la interfase IEmpleado, seleccionelo y en la lista de la derecha obtendremos lo que hay que implementar. En las propiedades obtendremos los Get y los Let a implementar. Notara que todas apareceren con el prefijo Private, esto porque mediante la implementación de otras propiedades o metodos usted decide si exponerlos al usuario de tu clase o no. Bueno, pues empecemos a implementar las propiedades. Para cada una de estas deberá crear sus respectivas variables privadas dentro de los módulos de clase CAgente y CDirectivo. Nombre: al igual que la clase de CEmpleado que ya tenemos de nuestra primera practica debera implementar el código para regresar o asignar el valor de nuestra variable privada para guardar en memoria el valor de nombre. Edad: al igual que la clase de CEmpleado que ya tenemos de nuestra primera practica debera implementar el código para regresar o asignar el valor de nuestra variable privada para guardar en memoria el valor de nombre. Sueldo: como sueldo se definió en la interfase de solo lectura, solo aparecerá el Get en la lista superior derecha. Seleccionela e implementela igual que el código de la clase CEmpleado que ya tenemos de nuestra primera practica. Como observamos arriba todas estas implementaciones de las propiedades son privadas. Requerimos de generar adentro de nuestras dos clases otras propiedades para poder exponer estos datos al usuario de mis clases pero sin el nombre de IEmpleado_Nombre sino simplemente como Nombre.
Página:32 de 66
Genere estas propiedades utilizando los conocimientos ya adquiridos anteriormente. Esto es, copiandolo de la clase que implementamos en la primera práctica: Nombre, Edad y Sueldo. Solo verifique que los nombres de las variables internas sean los mismos. Aqui hay que hacer una observación: note que tanto las propiedades de la interfase implementada y las propiedades a exponer ( Nombre, Edad, Sueldo ) contiene el mismo código. En este caso los podemos dejar así porque no es mas que una línea de codigo en estas propiedades, pero si fuera mas compleja la programación no repitiriamos el mismo codigo en ambas parte, sino que simplemente las propiedades a exponer mandarían llamar a las propiedades implementadas de IEmpleado para no duplicar código. Esto se vera más claro al implementar los métodos en el punto siguiente. Implemente los dos métodos de aumentar/disminuir sueldo que presenta la interface IEmpleado en ambas clases CAgente y CDirectivo. El código que se implementará en estos métodos son similares a los que se realizaron en CEmpleados en la primera practica. Solo que haremos algunas modificaciones. Para la clase CAgente: se le aumenta el sueldo si el sueldo actual es mayor o igual a 1500 y se le disminuye si el sueldo actual es mayor 499. Casos contrarios no se le aumenta o disminuye, respectivamente. Para la clase CDirectivos: se le aumenta el sueldo si el sueldo actual es mayor o igual 2000 y se le disminuye si el sueldo actual es mayor a 999. Casos contrarios no se le aumenta o disminuye. Ahora, tenemos que exponer estos métodos al usuario de nuestras clases. Por lo que deberá crear dos métodos público que se llamen: AumentaSueldo y DisminuyeSueldo en cada modulo de clase ( CAgente, CDirectivo ). Y como código dentro de estos no escriba lo mismo que se hizo en el paso anterior. Solo mande llamar al que ya se codifico. Por ejemplo, en AumentaSueldo mande llamar a IEmpleado_AumentaSueldo y regrese al cliente lo que éste regrese. Hasta el momento en nuestras dos clases ya tenemos codificada la implementación de las dos clases: CAgente y CDirectivo. Ahora vamos a añadir otras propiedades a cada uno respectivamente. Esto es, podemos tener otras propiedades o metodos expuestos al usuario diferentes a los que tiene la interface. En la clase CAgente: añada la siguiente propiedad: HorasTrabajadas: Single (L/E); en Let debera validar que este entre 4 hrs. y 10 hrs. (inclusives) sino no realice el cambio. En la clase CDirectivo: añada las siguientes propiedades: Prestaciones: Booleano (L/E); deberá tener True si este directivo tiene prestaciones, caso contrario False. En el evento Initialize de las clases creadas inicialicemos algunas variables: En la clase CAgente: inicialicemos las siguientes variables. Sueldo: inicialicelo a 1500. HorasTrabajadas: inicialicelo a 6.5 (suponemos que la jornada minima diaria de cada trabajador es de esta cantidad) En la clase CDirectivo: inicialicemos las siguientes variables. Sueldo: inicialicelo a 2000. Prestaciones: inicialicelo a False. Salvemos el proyecto. Dele un nombre descriptivo a cada módulo de clase. Ahora iremos a nuestro proyecto SysEmp.exe. Para hacer uso de estas dos clases. Siga los siguientes pasos cuidadosamente. Añadir una nueva forma al proyecto SysEmp.exe y llamésmola CatEmpleado2.
Página:33 de 66
Vayamos a las propiedades del proyecto ( SysEmp Properties del menú Project ) y se leccionesmos que la forma CatEmpleado2 es nuestra forma inicial al correr el proyecto. En la parte superior de la forma coloque dos OptionButton para indicar si el empleado a añadir es de tipo Agente o es de tipo Directivo. Ahora pongamos los respectivos Labels y Textbox para cada una de las siguientes propiedades: Nombre, Edad, Sueldo (recuerde que es de solo lectura), Horas Trabajadas. Para la propiedad Prestaciones utilice un CheckButton para habilitar si tiene prestaciones o no. Añadiremos ahora los acostumbrados botones: Añadir, Borrar, Aumentar, Disminuir . Definamos dos variables privadas en la sección de declaración del formulario, una para CAgente y otra para CDirectivo. Inicialicemos estas variables (o sea crear los objetos con Set.. New ) en el evento Initialize del formulario. En el evento Load de la forma inicialice el OptionButton de Agente a True para seleccionarlo. Generemos nuestro procedimiento privado Actualiza_Forma que reciba como parámetro la interface IEmpleado implementado en las clases CAgente y CDirectivo. Actualice los textos de Nombre, Edad y Sueldo que son los que obtenemos del parametro que recibimos de tipo IEmpleado. Ahora dentro del evento Click de los OptionButton vamos a meter el codigo necesario para realizar el cambio entre el objeto tipo CAgente y el objeto tipo CDirectivo. En el evento Click del OptionButton de Agente, realizaremos lo siguiente: inhabilite o esconda el control CheckBox de Prestaciones por que en este tipo de objeto no se requiere y habilite o haga visibles los controles correspondientes a HorasTrabajadas. Mande llamar a actualiza forma para desplegar a los textbox lo comun en ambos objetos, en seguida despliegue el valor de HorasTrabajadas del objeto de Agente. En el evento Click del OptionButton de Directivo, realizaremos lo siguiente: inhabilite o esconda los controles correspondientes a HorasTrabajadas por que en este tipo de objeto no se requieren y habilite o haga visibles el control CheckBox de Prestaciones. Mande llamar a actualiza forma para desplegar a los textbox lo comun en ambos objetos, en seguida despliegue el valor de Prestaciones del objeto de Directivo.
Vamos a agregar un módulo estandar a la aplicación SysEmp.exe para implementar una función general para aumentar el sueldo independientemente del objeto que se pase como parámetro, la restricción es que este objeto implemente la interface solicitada como párametro. En este módulo estándard insertado en el proyecto implemente una función publica que regresa un valor booleano que se llame CambiarSueldo el cual reciba como parametro una variable de interfase de tipo IEmpleado. Como segundo parámetro recibirá una variable que indique si se aumentará o se disminuira el sueldo. Finalmente, como tercer parametro recibirá el porcentaje a aumentar o disminuir. Dentro del código de esta funcion solo se ejecutará el metodo AumentaSueldo o DisminuyeSueldo , de acuerdo al segundo parametro recibido, de la interface implementada que se recibe como parámetro
Codifique los botones como sigue: Añadir : codifique este botón para igualar los datos actuales de los controles al objeto creado ya sea Agente o Directivo (los botones OptionButton lo indicaran). Puede utilizar validación de datos si lo desea. Borrar : de lo que se trata es que el objeto del empleado actual (ya sea agente o directivo, los OptionButton lo indicaran) deberá borrarse y crearse uno nuevo.
Página:34 de 66
Debera actualizar la forma al nuevo objeto (solo mande llamar al evento Click del OptionButton actualmente seleccionado). Aumentar : mendiante una caja de entrada (instrucción InputBox) obtener un valor entero entre 1 y 100, para poder aumentar el sueldo al Agente o Directivo actual, utilice la función CambiarSueldo creado en el punto anterior para aumentar el sueldo, solo pasele el objeto de Agente o Directivo que implementa la interface para enviarlo como parámetro a este procedimiento. Disminuir : igual que la anterior, pero se trata ahora de disminuir el sueldo. Salir : para salir de la aplicación o de la forma. Salve su proyectos y deles un nombre descriptivo a los archivos a guardar. Pruebelo. Ejecute la aplicación (F5) para ver nuestro objeto de empleado funcionando.
Página:35 de 66
Controles de Usuario Introducción: En esta sección aprenderemos a crear Controles de Usuario ( UserControl) , usando para esto un proyecto especial denominado Control de Usuario
Los controles ActiveX, que se llamaban antes controles OLE, son elementos estándar de interfaz de usuario que le permiten ensamblar rápidamente formularios y cuadros de diálogo. Los controles ActiveX también dan vida a Internet, agregando una nueva y atractiva funcionalidad a las páginas del World Wide Web. Diseñar un control ActiveX puede resultar tan fácil como diseñar un formulario de Visual Basic: puede usar los comandos gráficos de Visual Basic con los que está familiarizado para dibujar el control o bien crear un grupo de controles con los controles existentes. Los controles ActiveX se pueden depurar en proceso, de forma que puede pasar directamente desde el código del formulario de prueba al código del proyecto de control ActiveX. Puede agregar enlaces de datos a su control ActiveX de Visual Basic, de forma que un usuario pueda enlazar fácilmente los campos individuales del control con los campos correspondientes de una base de datos o de un origen de datos. Puede usar también enlaces de datos para crear un control ActiveX que puede enlazar con otros controles, similares al control Data de Visual Basic.
Lab05: Creación de un Control ActiveX (OCX) Paso a Paso Para crear el proyecto ControlDemo 1. En el menú Archivo, haga clic en Nuevo proyecto para abrir el cuadro de diálogo Nuevo proyecto. (Esto cerrará el proyecto o grupo de proyectos actual; se le pedirá que guarde los cambios que haya efectuado.) Haga doble clic en el icono Control ActiveX para crear un nuevo proyecto. Visual Basic agrega automáticamente al proyecto un diseñador UserControl. El nombre predeterminado, UserControl1, aparece como título del diseñador. 2. En el menú Proyecto, haga clic en Propiedades de Proyecto1 para abrir el cuadro de diálogo Propiedades del proyecto. Seleccione la ficha General, complete la información que se muestra en la imagen de la página siguiente y haga clic en Aceptar.
Página:36 de 66
3. Haga doble clic en UserControl1 en la ventana Explorador de proyectos para traer el diseñador al frente. 4. En la ventana Propiedades, haga doble clic en la propiedad Name y cambie el nombre del control de usuario a ShapeLabel. El nuevo nombre aparece en el título del diseñador y en la ventana Explorador de proyectos . El nombre que especifique se convertirá en el nombre de clase del control, igual que CommandButton es el nombre de clase de los botones de comando. "Crear controles ActiveX" proporciona instrucciones para elegir los nombres de clase de los controles. Observe que la ventana Propiedades tiene una apariencia muy parecida a la de un formulario de Visual Basic. Faltan algunas propiedades que está acostumbrado a ver y hay propiedades que no se encuentran en los formularios normales de Visual Basic. 5. Dentro del diseñador de controles, ajuste el tamaño del control mediante el controlador de arrastre situado en la esquina inferior derecha del control, arrastrándolo hacia arriba y a la izquierda para hacer el control más pequeño. De esta forma se establece el tamaño predeterminado del control. Para mayor comodidad en procedimientos posteriores, el control ShapeLabel debe tener un tamaño reducido. 6. En el menú Archivo, haga clic en Guardar proyecto para guardar los archivos del proyecto. Asígneles nombres como se muestra en la tabla siguiente. Visual Basic proporcionará las extensiones apropiadas automáticamente. Archivo Control de Usuario Proyecto
Nombre de archivo ControlDemo_ShapeLabel ControlDemo
Extensión .ctl .vbp
Página:37 de 66
Para agregar un proyecto de prueba al grupo de proyectos
7. En el menú Archivo, haga clic en Agregar proyecto para abrir el cuadro de diálogo Agregar proyecto. Importante No haga clic en Abrir proyecto o en Nuevo proyecto porque se cerraría el proyecto de control.
8. Haga doble clic en el icono EXE estándar para agregar un proyecto .exe normal. Ahora puede ver ambos proyectos en la ventana Explorador de proyectos y el título de la ventana Explorador de proyectos muestra el nombre predeterminado del grupo de proyectos.
El nuevo proyecto se convierte inmediatamente en el proyecto inicial para el grupo de proyectos. La ventana Explorador de proyectos identifica el proyecto inicial mostrando su nombre en negrita. Un proyecto de control ActiveX, como ControlDemo, no puede ser el proyecto inicial. 9. En el menú Archivo, haga clic en Guardar grupo de proyectos para guardar el proyecto de prueba y el grupo de proyectos. Asigne nombre a los archivos como se muestra a continuación. Visual Basic proporcionará automáticamente las extensiones indicadas. Archivo
Nombre de Archivo
Extensión
Formulario Proyecto Grupo de Proyectos
TestCtlDemo_Form1 TestCtlDemo ControlDemo
.frm .vbp .vbg
Para agregar código al evento Resize
1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para convertirlo en el diseñador activo.
Página:38 de 66
2. Haga doble clic en el control ShapeLabel para abrir la ventana de código. 3. En el cuadro Procedimiento, haga clic en el evento Resize para ir a su procedimiento de evento. Agregue el código siguiente: Private Sub UserControl_Resize() Static intCt As Integer intCt = intCt + 1 Debug.Print "Resize" & intCt End Sub
Para ejecutar el control ShapeLabel en tiempo de diseño
1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para traer su diseñador al frente y, después, presione Ctrl-F4 para cerrar la ventana. Al cerrar la ventana del diseñador, el control ShapeLabel se pone en modo de ejecución. En cuanto el control está en modo de ejecución, su icono (el icono predeterminado del cuadro de herramientas para un control de usuario) se activa en el cuadro de herramientas. No haga clic en el botón Iniciar de la barra de herramientas ni presione F5 porque pondría todo el grupo de proyectos en modo de ejecución y no podría agregar el nuevo control a un formulario. Importante
Cuando pone un control en modo de ejecución, no importa cómo cierre la ventana del diseñador. (Siempre puede saber si el diseñador está abierto porque el icono del control en el cuadro de herramientas aparecerá en color gris.) 2. En la ventana Explorador de proyectos, haga doble clic en Form1 para traerlo al frente. 3. Haga doble clic en el icono ShapeLabel para agregar un control ShapeLabel a Form1. El control aparece como un rectángulo plano gris con controladores de tamaño:
En la ventana Propiedades puede ver las propiedades predeterminadas para un control nuevo. Al control ShapeLabel que acaba de agregar al formulario se le ha asignado un nombre predeterminado, ShapeLabel1. Asignar nombre a un control cuando comienza el diseño evita confusiones. Suponga que coloca un control con un nombre predeterminado, como UserControl1, en un formulario. La numeración automática de los nuevos controles agregaría un número al final del nombre del control, lo que daría como resultado un nombre confuso como UserControl11. Nota
Página:39 de 66
4. Al colocar en el formulario el control ShapeLabel se ha producido el evento Resize del mismo, como puede ver en la ventana Inmediato. Utilice los controladores de tamaño para cambiar varias veces el tamaño del control. Cada vez que cambia el tamaño se vuelve a producir el evento Resize. Si se limita a mover el control por el formulario, no se produce el evento Resize. 5. En Form1, haga doble clic en el control ShapeLabel para abrir la ventana de código de Form1. El cursor estará situado en el procedimiento de evento predeterminado, ShapeLabel1_GotFocus. Puede usar el cuadro Procedimiento para ver los otros tres eventos que Visual Basic proporciona automáticamente para el control. Cierre la ventana de código cuando haya terminado. 6. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para abrir el diseñador de ShapeLabel. Observe que el control ShapeLabel que ha colocado en Form1 está sombreado con unas marcas rayadas para indicar que está inactivo.
Abrir el diseñador de un control hace que todas las instancias del control queden inactivas. Cambiar el código en la ventana de código del control también convierte en inactivas las instancias del control. 7. El código contenido en el módulo de código de ShapeLabel no se puede ejecutar mientras esté abierto el diseñador. Utilice los controladores de tamaño para cambiar el tamaño del control ShapeLabel sombreado en Form1. El evento Resize no se activa, por lo que no aparecen mensajes nuevos en la ventana Inmediato. 8. Asegúrese de que el diseñador de ShapeLabel está en el frente y presione Ctrl-F4 para cerrar la ventana, reactivando así la instancia del control. Desaparecerá el sombreado del control en Form1, lo que indica que la instancia está activa otra vez.Si el control se ha convertido en inactivo a causa de los cambios efectuados en su código, puede hacer clic con el botón secundario del mouse (ratón) en el formulario de prueba para llamar a su menú contextual y hacer clic en Actualizar controles de usuario para volver a activar las instancias del control. Nota Debido al número de ventanas que requieren estos procedimientos, puede encontrarse a menudo con que el diseñador de ShapeLabel ha desaparecido detrás de otro formulario. Puede hacer doble clic en ShapeLabel en la ventana Explorador de proyectos para traer el diseñador al frente.
Página:40 de 66
Tiempos y vida de un objeto UserControl La vida de un formulario normal de Visual Basic está marcada por ciertos eventos clave, como Initialize, Load, QueryUnload y Unload. Para crear aplicaciones que funcionen bien es importante saber cuándo se producen estos eventos en el ciclo de vida de un formulario. Lo mismo sucede con los controles. Los eventos clave en el ciclo de vida de un control de usuario son Initialize, InitProperties, ReadProperties, WriteProperties y Terminate. El procedimiento siguiente explora estos eventos.
Para observar los eventos clave de ShapeLabel
1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para abrir su diseñador. 2. Haga doble clic en el diseñador para abrir una ventana de código para ShapeLabel y escriba el código en los siguientes procedimientos de evento: Private Sub UserControl_Initialize() Debug.Print "Initialize" End Sub Private Sub UserControl_InitProperties() Debug.Print "InitProperties" End Sub Private Sub UserControl_ReadProperties(PropBag As PropertyBag) Debug.Print "ReadProperties" End Sub Private Sub UserControl_WriteProperties(PropBag As PropertyBag) Debug.Print "WriteProperties" End Sub Private Sub UserControl_Terminate() Debug.Print "Terminate" End Sub
Para los objetos UserControl, Load y Unload se sustituyen por los eventos ReadProperties y WriteProperties. Esto se explica con más detalle en "Descripción del tiempo de vida y los eventos clave de un control", en "Crear controles ActiveX". Nota
3. Asegúrese de que el diseñador de ShapeLabel está en el frente y, entonces, presione Ctrl-F4 para cerrar la ventana, poniendo así el control en modo de ejecución. Aparecerán mensajes de depuración en la ventana Inmediato:
Qué está pasando aquí? No ha colocado otra instancia del control ShapeLabel en Form1. ¿De dónde han salido todos estos eventos?
Página:41 de 66
Este ejemplo ilustra un punto importante sobre los controles. Un usuario coloca un control en un formulario y piensa que a partir de ahí el control es un componente fijo y permanente del formulario. Pero desde la perspectiva del autor de controles, estos se destruyen y se vuelven a crear continuamente. Al poner ShapeLabel en modo de ejecución cerrando su diseñador, la instancia de ShapeLabel en Form1 se ha destruido y se ha vuelto a crear. En ese momento ha recibido un evento Initialize. ¿Por qué no ha visto primero un evento Terminate? Porque la instancia original de ShapeLabel que ha colocado en Form1 se ha creado antes de que agregara el código contenido en el procedimiento de evento UserControl_Terminate. ¡Bienvenido al mundo extravagante y complejo de la creación de controles! Nota Las instancias de un control también se destruyen y se vuelven a crear cuando hace clic en Actualizar controles de usuario en el menú contextual del formulario. 4. Presione Ctrl-F5 o haga clic en el botón Iniciar de la barra de herramientas para ejecutar TestCtlDemo. Durante la ejecución del proyecto desaparece la cuadrícula de Form1, por eso no puede ver el control ShapeLabel, pero puede ver ante sus ojos cómo parpadea en la ventana Inmediato:
Cuando el UserControl se ejecuta, la instancia en tiempo de diseño se destruye...
...Y se crea una instancia en tiempo de ejecución del mismo control
Después de crear una instancia de control, el evento ReadProperties le ofrece la oportunidad de obtener los valores de las propiedades del control guardados en el archivo .frm, que pertenece al formulario que contiene la instancia del control. Cuando se destruye la instancia en tiempo de diseño del control, el evento WriteProperties le da la oportunidad de guardar los valores de propiedades establecidos en tiempo de diseño por el desarrollador que está utilizando su control. Los valores de las propiedades se guardan en el archivo .frm del formulario contenedor, como veremos en "Guardar los valores de las propiedades del control ShapeLabel", más adelante en este mismo capítulo. El evento Terminate se produce cuando se está destruyendo el control. 5. Cierre Form1 para volver al modo de diseño. En la ventana Inmediato verá un evento Terminate a medida que se destruye la instancia en tiempo de ejecución de ShapeLabel (pero no verá WriteProperties, ¿por qué?). Después verá los eventos
Página:42 de 66
Initialize, ReadProperties y Resize, a medida que se crea la instancia en tiempo de diseño del control. La instancia en tiempo de ejecución de un control no obtiene nunca un evento riteProperties, porque no necesita guardar los valores de sus propiedades. Para entender por qué no, considere el futuro de ShapeLabel. Cuando esté compilado en un archivo .ocx, lo agregará a otro proyecto, pondrá una instancia en un formulario, compilará el proyecto en un archivo .exe y lo ejecutará. Cuando cierre ese archivo .exe, el único sitio en que la instancia de ShapeLabel podría guardar sus propiedades sería el archivo .exe. Los buenos sistemas operativos no toleran este tipo de comportamiento. 6. Desplácese a la parte superior de la ventana Inmediato, haga clic en la esquina superior izquierda y arrastre para seleccionar todo el texto de la ventana. Presione la tecla SUPR para borrar el contenido de la ventana. 7. En la ventana Explorador de proyectos, haga doble clic en Form1 para traer al frente el Form1. 8. En el Cuadro de herramientas, haga doble clic en el icono ShapeLabel para agregar otra instancia del control al Form1. Esta vez verá un nuevo evento. Cuando agrega una nueva instancia de este control al formulario, se obtiene el evento InitProperties, en el que se obtienen los valores predeterminados de la propiedad
Cuando se sitúa una nueva instancia del control en un contenedor, obtiene un evento InitProperties. En el procedimiento de evento UserControl_InitProperties puede escribir código para: Establecer los valores predeterminados para cada valor de las propiedades del control Realizar tareas siempre que un usuario crea una instancia del control. 9. Cierre el diseñador de Form1 haciendo clic en su botón Cerrar o presionando Ctrl-F4 mientras el diseñador está en el frente. En la ventana Inmediato verá dos conjuntos de eventos WriteProperties y Terminate, uno para cada instancia de ShapeLabel. 10. En la ventana Explorador de proyectos, haga doble clic en Form1 para abrir otra vez su diseñador. Cuando se abre el diseñador, se crean todos los controles del Form1 y se activan sus eventos Initialize. Entonces todos los controles reciben eventos ReadProperties, que les permiten recuperar los valores guardados de sus propiedades. El evento InitProperties no se produce, porque ya existen las dos instancias del control ShapeLabel.
Dibujar el control ShapeLabel Puede usar métodos gráficos, como Circle y Line, para dibujar el control o bien puede crear la apariencia del control usando los controles ActiveX y los controles intrínsecos de Visual Basic existentes. Los controles que se agregan a UserControl para crear su apariencia se denominan controles componentes. Como sugiere su nombre, la apariencia de ShapeLabel se crea usando un control Shape y un control Label. Página:43 de 66
Para agregar controles componentes al control ShapeLabel 1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para abrir su diseñador. 2. En el Cuadro de herramientas, haga doble clic en el control Visual Basic Shape para colocar un control Shape en el diseñador de ShapeLabel. Si no ha utilizado antes el control Shape, mantenga el mouse sobre los botones del cuadro de herramientas hasta que encuentre uno cuya Información sobre herramientas sea "Shape". 3. En la ventana Propiedades, establezca los siguientes valores de propiedades para el control Shape: Propiedad
Valor
BorderStyle
0 - Transparent
FillColor
&H000000FF (Rojo)
FillStyle
0 – Solid
Name
ShpBack
Shape
2 – Oval
Nota Para establecer propiedades de color como FillColor y ForeColor a colores específicos, seleccione la ficha Paleta del cuadro de diálogo de selección de color.
4. En el Cuadro de herramientas, haga doble clic en el control Label para agregar una etiqueta encima del control Shape. En la ventana Propiedades, establezca los siguientes valores de propiedades para el control Label: Propiedad
Valor
Alignment
2 - Center 0 - Transparent &H00FFFFFF (Blanco) lblCaption
BackStyle ForeColor Name
5. Use el controlador inferior de tamaño para cambiar el alto de la etiqueta de forma que sea algo más alta que el texto que contiene. ShapeLabel debe tener una apariencia similar a ésta:
Página:44 de 66
6. Haga doble clic en el diseñador de ShapeLabel para traer al frente la ventana de código y sustituya el código del procedimiento de evento UserControl_Resize con el siguiente código: Private Sub UserControl_Resize() ' Da tamaño al control Shape para llenar el ' área visible de ShapeLabel. shpBack.Move 0, 0, ScaleWidth, ScaleHeight ' Centra verticalmente el control Label y ' lo hace del mismo ancho que ShapeLabel. lblCaption.Move 0, (ScaleHeight - lblCaption.Height) / 2, ScaleWidth End Sub
7. Cuando esté diseñando un control de usuario, recuerde que el área con la que tiene que trabajar está enlazada por los valores ScaleWidth y ScaleHeight del control. Aparte de esto, nada es visible para el usuario del control. Además, el tamaño del área de cliente cambiará a voluntad del usuario. Por eso, el evento Resize es uno de los eventos más importantes del diseño de controles. 8. Asegúrese de que el diseñador de ShapeLabel está en el frente y, entonces, presione Ctrl-F4 para cerrar la ventana, poniendo así ShapeLabel en modo de ejecución. En la ventana Explorador de proyectos, haga doble clic en Form1 para traerlo al frente. 9. Los dos controles ShapeLabel deben aparecer ahora como óvalos rojos, con títulos blancos centrados con el texto "Label1". Cambie el tamaño de ambos controles ShapeLabel para probar el código del evento Resize.
Guardar los valores de las propiedades del control ShapeLabel Es posible agregar propiedades y métodos a un control ActiveX de la misma forma que se agregan a los módulos de clase: creando procedimientos públicos. Como ShapeLabel va a ser un control de etiqueta mejorado, es lógico que tenga una propiedad Caption. El procedimiento siguiente agrega una propiedad Caption y el código de soporte para guardar y recuperar el valor de la propiedad. Los valores de las propiedades de un control se guardan junto con los demás datos que describen el contenedor, en este caso, Form1.
Para agregar una propiedad Caption al control ShapeLabel
Página:45 de 66
1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para abrir su diseñador y haga doble clic en ShapeLabel para traer al frente la ventana de código. 2. En el menú Herramientas, haga clic en Agregar procedimiento para abrir el cuadro de diálogo Agregar procedimiento. En el cuadro Nombre, escriba el nombre. Haga clic en Propiedad y en Público y, después, haga clic en Aceptar. 3. En la ventana de código, cambie los procedimientos Property recién creados para que aparezcan de la forma siguiente: Public Property Get Caption () As String Caption = lblCaption.Caption End Property Public Property Let Caption(ByVal NewCaption As String) lblCaption.Caption = NewCaption PropertyChanged "Caption" End Property
El procedimiento Property Let se ejecuta siempre que se asigna un nuevo valor a la propiedad Caption. Almacena el nuevo valor directamente en la propiedad Caption de la etiqueta lblCaption de ShapeLabel. El procedimiento Property Get se ejecuta siempre que se recupera el valor de la propiedad. Lee el valor almacenado en la propiedad Caption de la etiqueta lblCaption. 4. Para inicializar la propiedad Caption, agregue el código siguiente al procedimiento de evento UserControl_InitProperties: Private Sub UserControl_InitProperties() ' Permitir que el valor de inicio de la propiedad ' Caption sea el nombre dado a esta instancia ' de ShapeLabel. Caption = Extender.Name Debug.Print "InitProperties" End Sub
Qué es este objeto Extender? Para el usuario de un control, las propiedades de ampliación (como Name, Top y Left) parecen formar parte del control. Pero las proporciona realmente el contenedor en el que está colocado el control. El objeto Extender de UserControl da al diseñador del control acceso a estas propiedades desde dentro del control. La propiedad de sólo lectura Name del objeto Extender devuelve el nombre que da el contenedor (o el usuario) a una instancia específica del control. Usar este nombre (por ejemplo, ShapeLabel1) como valor inicial de la propiedad Caption imita el comportamiento del control Label. Sugerencia Si el control imita el comportamiento de controles que proporcionan una funcionalidad similar, será más intuitivo usarlo. ¿Qué ocurriría si creara una propiedad Name para el control? Podría tener acceso a ella desde dentro del control, pero la única propiedad Name que vería el usuario sería la propiedad Name del objeto Extender. Esta pregunta introduce un tema recurrente de los controles: El contenedor determina una gran parte del comportamiento y la apariencia del control. Es el contenedor lo que determina la propiedad Name del control, y las propiedades Top y Left se mantienen en relación a las coordenadas relativas del contenedor. Este tema se retomará en "Crear controles ActiveX". Una última cuestión relacionada con este asunto: ¿por qué se pone este código en el evento InitProperties? ¿Por qué no se utiliza el evento Initialize? Como ya hemos visto, se llama a Initialize cada vez que se crea una instancia del control, lo que sucede a menudo. InitProperties sólo se produce cuando el usuario coloca el control
Página:46 de 66
en el contenedor. Por eso es el sitio apropiado para establecer los valores iniciales de una instancia de control. Además, los objetos Extender y AmbientProperties del objeto UserControl no están disponibles aún cuando se produce el evento Initialize. "Descripción de la duración y los eventos clave de un control", en "Crear controles ActiveX", explica los usos apropiados del evento Initialize. 5. Para guardar el valor de la propiedad Caption, agregue el código siguiente al procedimiento de evento UserControl_WriteProperties: Private Sub UserControl_WriteProperties(PropBag As PropertyBag) Debug.Print "WriteProperties" PropBag.WriteProperty "Caption", Caption, Extender.Name End Sub
PropertyBag es una "bolsa" en la que se guardan los valores de las propiedades. Esta bolsa la proporciona el contenedor. No puede ver su contenido, ni puede saber dónde o cómo se guardan los datos. Todo lo que puede hacer es colocar valores en ella y extraerlos. El primer argumento del método WriteProperty es el nombre de la propiedad, que se usará como clave de recuperación de datos. Para este argumento debe usar el nombre de la propiedad, ya que aparecerá en el archivo de texto .frm (en Visual Basic; otros contenedores pueden usar otros nombres de archivo para guardar datos de proyectos) y lo podrá ver el usuario del control. El segundo argumento es el valor. El valor de una propiedad se guarda como un tipo Variant. El tercer argumento, por extraño que parezca, es un valor predeterminado. ¿Por qué proporcionar un valor predeterminado cuando se está guardando el valor de la propiedad? Antes de guardar el valor, el método WriteProperty compara el valor de la propiedad con el predeterminado. Si son iguales, no es necesario guardar el valor de la propiedad, porque los valores predeterminados se establecerán automáticamente al volver a cargar el control. De esta forma se evita llenar el archivo .frm con cientos de entradas predeterminadas, lo que a buen seguro agradecerán los usuarios. 6. Coloque el código siguiente en el evento ReadProperties para recuperar el valor persistente de la propiedad Caption: Private Sub UserControl_ReadProperties(PropBag As PropertyBag) Debug.Print "ReadProperties" Caption = PropBag.ReadProperty("Caption", Extender.Name) End Sub
El segundo argumento del método ReadProperty es un valor predeterminado que se usará si no se ha guardado ningún valor, si el usuario ha eliminado la propiedad del archivo de texto o si el valor no ha cambiado nunca con respecto al valor predeterminado y, por tanto, WriteProperty nunca lo ha guardado. 7. Asegúrese de que el diseñador de ShapeLabel está en el frente y, después, haga clic en el botón Cerrar o presione Ctrl-F4 para cerrar la ventana, poniendo así el control en modo de ejecución. Como por arte de magia, los títulos de los controles ShapeLabel cambian para coincidir con los nombres predeterminados de las dos instancias, ShapeLabel1 y ShapeLabel2. Utilice la ventana Propiedades para cambiar las propiedades Caption de los dos controles ShapeLabel del Form1 y haga clic en el botón Cerrar del diseñador de Form1. En la ventana Explorador de proyectos, haga doble clic en Form1 para volver a abrir el diseñador de Form1. A partir de los mensajes de la ventana Inmediato, puede ver que los controles se han destruido y se han vuelto a crear, pero los valores de las propiedades Caption se han guardado y recuperado.
Página:47 de 66
8. Presione Ctrl-F5 para ejecutar TestCtlDemo, el proyecto inicial del grupo de proyectos, y observe el comportamiento del control ShapeLabel en tiempo de ejecución. 9. Haga clic en el botón Cerrar del Form1 para volver al modo de diseño.
Dar una página de propiedades al control ShapeLabel Las propiedades simples que se crean usando procedimientos Property aparecerán automáticamente en la ventana Propiedades de Visual Basic. También puede conectar el control a páginas de propiedades, que muestran las propiedades del control en un formato alternativo. Cada página de propiedades que se conecta al control se convierte en una de las fichas del cuadro de diálogo Propiedades con fichas. Visual Basic controla todos los detalles de presentar las páginas como un cuadro de diálogo con fichas y administra los botones Aceptar, Cancelar y Aplicar. Todo lo que tiene que hacer es diseñar los controles que se usarán para establecer los valores de las propiedades. La páginas de propiedades son útiles cuando un grupo de propiedades interactúa de forma compleja, como ocurre con el control Toolbar incluido en Visual Basic. También son útiles para los controles que se van a distribuir internacionalmente, porque se pueden traducir los títulos a diferentes idiomas. Las páginas de propiedades también le permiten usar los controles con herramientas de desarrollo que no tienen una ventana P ropiedades.
Para agregar una página de propiedades al proyecto 1. En la ventana Explorador de proyectos, haga clic en ControlDemo para seleccionar el proyecto del control. En el menú Proyecto, haga clic en Agregar página de propiedades para abrir el cuadro de diálogo Agregar página de propiedades. Haga doble clic en el icono Página de propiedades para agregar una página de propiedades al proyecto. 2. En la ventana Propiedades, haga doble clic en la propiedad Name y cambie el nombre de la página de propiedades a SLGeneral. Haga doble clic en la propiedad Caption y cambie el título a General. El título es lo que aparecerá en la ficha de la página de propiedades cuando esté en uso. ¿Por qué llamar a la página SLGeneral en lugar de General? Puede que tenga varios controles en un proyecto y cada uno de ellos tenga una página General. Ésta es la página General del control ShapeLabel. 3. En el menú Archivo, haga clic en Guardar grupo de proyectos para guardar el grupo de proyectos. Asigne nombre a la página de propiedades como se indica en la tabla siguiente. Visual Basic agregará automáticamente la extensión indicada. Archivo
Nombre de archivo
Extensión
Página de propiedades
ControlDemo_SLGeneral
.pag
La información binaria de una página de propiedades, como los mapas de bits, se guardarán en un archivo binario con el mismo nombre y una extensión .pgx.
El diseñador de una página de propiedades se parece mucho al diseñador de un control, excepto en que la barra de título del diseñador muestra la propiedad Caption de la página de propiedades, en lugar de la propiedad Name.
Página:48 de 66
Para diseñar la página de propiedades General para el control ShapeLabel 1. Coloque un control Label en la página de propiedades y establezca la propiedad Caption de la etiqueta a la palabra Título. 2. Debajo de la etiqueta, coloque un control TextBox y asígnele los siguientes valores de propiedades: Propiedad
Valor
Name Text
txtCaption
La página de propiedades debe parecerse a la que se muestra a continuación.
Colocar la etiqueta de descripción de la propiedad encima del cuadro de texto de esta forma facilita la traducción del componente del control a otros idiomas, en los que la palabra "Título" puede ser más corta o más larga.
3. Haga doble clic en la página de propiedades para abrir una ventana de código. En la lista desplegable Eventos, seleccione el evento SelectionChanged y agregue el código siguiente: Private Sub PropertyPage_SelectionChanged() ' Muestra el título del primer control de ' la lista de controles seleccionados ' actualmente. txtCaption.Text = SelectedControls(0).Caption End Sub
La finalidad de este evento es obtener los valores existentes de propiedades del control o controles ShapeLabel que están seleccionados en este momento. No hay ningún problema; puede haber más de un control ShapeLabel seleccionado. La selección múltiple es muy práctica para el usuario del control, pero implica más trabajo para el diseñador. Una página de propiedades recibe un evento SelectionChanged cada vez que se abre. También recibe este evento cuando cambia la lista de controles seleccionados. Esto es necesario porque el cuadro de diálogo Páginas de propiedades no es modal, de forma que el usuario puede seleccionar controles adicionales mientras está abierto el cuadro de diálogo. Tiene que decidir cómo controlar la selección múltiple basándose en cada propiedad. Por ejemplo, si la página de propiedades muestra la propiedad Width del primer control de la colección SelectedControls, es decir, SelectedControls(0), como se muestra arriba en el código, será fácil para el usuario cambiar el ancho de todos los controles seleccionados a ese valor.
Por otra parte, no tiene sentido establecer los títulos de todos los controles ShapeLabel de un formulario al mismo valor: lo más lógico que se puede hacer con la
Página:49 de 66
propiedad Caption es desactivar txtCaption si la propiedad Count de la colección SelectedControls es mayor que uno. Sin embargo, este procedimiento no hace lo lógico. Con fines ilustrativos se permite que la página de propiedades establezca varios títulos. Después, si desea activar el comportamiento descrito anteriormente, puede agregar las líneas de código siguientes al procedimiento de evento PropertyPage_SelectionChanged: ' ¡No haga esto todavía! If SelectedControls.Count > 1 Then txtCaption.Enabled = False Else txtCaption.Enabled = True End If
4. Para establecer los valores de las propiedades de todos los controles seleccionados actualmente, agregue el código siguiente al evento ApplyChanges: Private Sub PropertyPage_ApplyChanges() ' Use una variable genérica Object, en caso de ' estar seleccionado más de un tipo de control. Dim objControl As Variant For Each objControl In SelectedControls objControl.Caption = txtCaption.Text Next End Sub
La página de propiedades recibirá el evento ApplyChanges cuando el usuario haga clic en el botón Aplicar o en Aceptar del cuadro de diálogo Páginas de propiedades. ¿Cómo sabe que cada control de SelectedControls tiene una propiedad Caption? Como diseñador del componente del control, usted determina qué páginas de propiedades están conectadas a un control dado. Una página de propiedades sólo aparecerá si todos los controles seleccionados actualmente tienen esa página en la lista Páginas de propiedades. Lo más fácil es asegurarse de que las páginas asignadas a cada control no muestran propiedades que no tiene el control. Si desea usar una página de propiedades de uso general para una serie de controles, y en la página de algunos de esos controles no se muestran todas las propiedades, puede agregar código al evento ApplyChanges para probar el tipo de control y aplicar el valor de propiedad que sea apropiado. Como alternativa, puede usar una instrucción On Error para interceptar y pasar por alto los errores de los controles que no tienen esa propiedad. Sólo tiene que preocuparse de los controles de su componente, ya que los controles que no forman parte de él nunca usarán las páginas de propiedades del componente. "Crear páginas de propiedades para los controles ActiveX" explica el diseño y la asignación de las páginas de propiedades con más detalle. 5. Para activar el botón Aplicar del cuadro de diálogo Páginas de propiedades cuando se ha modificado la propiedad Caption, agregue el código siguiente al evento Change del cuadro de texto txtCaption: Private Sub txtCaption_Change() ' La propiedad Changed de la página de ' propiedades controla el botón Aplicar del ' cuadro de diálogo Página de propiedades. Changed = True End Sub
6. En la ventana Explorador de proyectos, haga doble clic en SLGeneral para traer al frente el diseñador de páginas de propiedades. Haga clic en el botón Cerrar del diseñador o presione Ctrl-F4 para cerrar el diseñador y poner la página en modo de ejecución. Al igual que los objetos UserControl, los objetos PropertyPage deben ejecutarse mientras el resto del grupo de proyectos está en modo de diseño.
Página:50 de 66
Para conectar la página de propiedades al control ShapeLabel 1. En la ventana Explorador de proyectos, haga doble clic en ShapeLabel para abrir el diseñador. 2. En la ventana Propiedades, haga doble clic en la propiedad PropertyPages para ver el cuadro de diálogo Conectar páginas de propiedades .
El cuadro de diálogo Conectar páginas de propiedades se puede usar para conectar múltiples páginas a un control de usuario y para controlar el orden de presentación de las fichas del cuadro de diálogo Páginas de propiedades para el control. 3. Active SLGeneral y haga clic en Aceptar. 4. Traiga al frente el diseñador de ShapeLabel y después haga clic en su botón Cerrar o presione Ctrl-F4 para poner el control ShapeLabel en modo de ejecución. 5. En la ventana Explorador de proyectos, haga doble clic en Form1 para abrir su diseñador. 6. Haga clic con el botón secundario del mouse (ratón) en uno de los controles ShapeLabel del Form1 para ver el menú contextual y haga clic en Propiedades para presentar el cuadro de diálogo Páginas de propiedades. 7. En el cuadro Caption de la ficha General, sustituya el título actual por un nuevo valor. Cuando lo hace, se activa el botón Aplicar. Haga clic en el botón Aplicar para cambiar el título del control. Nota También puede cambiar el título presionando Aceptar, pero de esta forma cerraría el cuadro de diálogo Páginas de propiedades. El cuadro de diálogo debe permanecer abierto para el paso siguiente.
8. Mantenga presionada la tecla CTRL y haga clic en el segundo control ShapeLabel del Form1, de forma que estén seleccionados ambos controles ShapeLabel. Cambie el título y haga clic en el botón Aplicar para establecer ambos títulos al mismo valor.
Página:51 de 66
Si lo desea, pruebe a agregar otros controles, como botones de comando, al Form1 y observe los efectos de las selecciones múltiples en el cuadro de diálogo Páginas de propiedades. 9. Cuando haya terminado de experimentar, haga clic en Aceptar para cerrar el cuadro de diálogo Páginas de propiedades.
Agregar un evento al control ShapeLabel Es importante distinguir entre los eventos que recibe el objeto UserControl (o los controles que contiene) y los eventos que desencadena el control. Los eventos que recibe el control son oportunidades para que usted haga algo interesante, mientras que los eventos que desencadena el control proporcionan oportunidades para que el programador que usa ese control haga algo interesante. Hay muchos eventos que podrían ser de interés para el usuario del control ShapeLabel. El control Label de Visual Basic desencadena un evento Click y ShapeLabel es solamente una etiqueta atractiva, por lo que el procedimiento siguiente agregará un evento Click. Para hacer el evento más interesante, sólo se desencadenará si el usuario hace clic en el segundo plano del óvalo. Para agregar un evento Click al control ShapeLabel 1. En la ventana Explorador de proyectos, haga clic en ShapeLabel para seleccionarlo y, después, presione F7 o haga clic en el botón Código de la barra de herramientas de dicha ventana para abrir la ventana Código. 2. En el cuadro Objeto, seleccione (General). En el cuadro Procedimiento, seleccione (Declaraciones) para colocarse en la parte superior del módulo de código. Agregue el código siguiente: Option Explicit ' Declara un evento Click público sin argumentos. Public Event Click()
3. En el cuadro Objeto, seleccione lblCaption. En el cuadro Procedimiento, seleccione el evento Click para el control Label. Agregue el código siguiente al procedimiento de evento lblCaption_Click: Private Sub lblCaption_Click() ' Desencadena un evento Click siempre que el ' usuario hace clic en la etiqueta. RaiseEvent Click End Sub
El código anterior desencadena un evento Click sólo si el usuario hace clic en lblCaption del control componente. Para los usuarios será más natural poder hacer clic en cualquier parte del segundo plano del óvalo de ShapeLabel; por eso el paso siguiente muestra cómo desencadenar el evento Click si el usuario hace clic en el óvalo coloreado. 4. En el cuadro Objeto, seleccione UserControl. En el cuadro Procedimiento, seleccione el evento MouseUp de UserControl. Agregue el código siguiente al procedimiento de evento UserControl_MouseUp: Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single) ' Desencadena un evento Click sólo si el color ' del punto en que se ha hecho clic es igual al
Página:52 de 66
' color del control Shape. Ignora los clics ' que se hacen fuera del óvalo. If Point(X, Y) = shpBack.FillColor Then RaiseEvent Click End If End Sub
Determinar si se ha producido un evento en una ubicación determinada se conoce como prueba de llamada. Cabría esperar que el código de la prueba de llamada se coloque en el procedimiento de evento shpBack_Click, ya que shpBack vuelve a cambiar de tamaño siempre para cubrir toda la superficie del control ShapeLabel. Pero los controles Shape no reciben eventos Click. En su lugar, el evento Click lo recibe el objeto que contiene el control Shape, que en este caso es el objeto UserControl. "Dibujar el control", en "Crear controles ActiveX", explica el uso de fondos transparentes para crear controles con forma irregular. 5. En la ventana Explorador de proyectos, haga clic en Form1 para seleccionarlo y, después, presione F7 o haga clic en el botón Código de la barra de herramientas de dicha ventana para abrir la ventana Código. 6. En el cuadro Objeto, seleccione uno de los controles ShapeLabel que ha agregado al Form1. En el cuadro Procedimiento, seleccione el evento Click. Nota Si no aparece el evento Click, asegúrese de que está cerrado el diseñador de ShapeLabel. Agregue el código siguiente al procedimiento de evento ShapeLabel1_Click: Private Sub ShapeLabel1_Click() MsgBox "¡Gracias por hacer clic! Mi " & "título es: " & ShapeLabel1.Caption End Sub
Nota Si el control ShapeLabel que ha seleccionado no se llama ShapeLabel1, utilice el nombre apropiado cuando escriba el código anterior. Puede hacer clic en la flecha del cuadro Procedimiento para ver todos los eventos del control ShapeLabel. Además del evento Click, hay otros cuatro eventos (DragDrop, DragOver, GotFocus y LostFocus) que proporciona automáticamente el contenedor, Form1. 7. En la barra de herramientas, haga clic en el botón Iniciar o presione Ctrl-F5 para ejecutar TestCtlDemo. Haga clic en varios lugares del formulario y del control ShapeLabel para comprobar que el evento Click sólo se desencadena sólo cuando hace clic dentro del fondo del óvalo. 8. Hay un fallo sutil en la prueba de llamada para el evento Click de ShapeLabel. Para verlo, presione el botón del mouse mientras el puntero está en la mitad inferior del óvalo rojo. Manteniendo presionado el botón del mouse, mueva con cuidado el puntero hasta que la punta de la flecha esté sobre el texto blanco del título de ShapeLabel y suelte luego el botón del mouse. ¡El cuadro de mensajes no aparece! El procedimiento de evento lblCaption_Click no se ejecuta porque el evento MouseDown se ha producido sobre UserControl. Por tanto, cuando se produce el evento MouseUp, lo recibe UserControl, aunque el mouse se haya movido hasta estar completamente fuera de Form1. El código de la prueba de llamada del evento MouseUp funciona si se suelta el botón del mouse encima del fondo rojo que asoma a través del fondo transparente de lblCaption, pero no funciona si se suelta el botón sobre el color blanco de primer plano del texto. (Si el botón se suelta fuera de ShapeLabel, la función Point devuelve
Página:53 de 66
-1, por lo que soltar el botón del mouse encima de cualquier punto rojo aleatorio no desencadenará el evento Click.) Arreglar este fallo se deja como ejercicio para el lector. (Sugerencia: mover la prueba de llamada al evento Click de UserControl no servirá de nada, porque el evento Click no se produce cuando el evento MouseUp se desencadena sobre un objeto diferente al del evento MouseDown.)
Compilar el componente ControlDemo Una vez creado un proyecto de control ActiveX que contiene uno o más objetos UserControl, puede compilarlo en un archivo .ocx y usar los controles en otras aplicaciones. Los siguientes procedimientos muestran la forma de hacerlo.
Para compilar el proyecto ControlDemo 1. Si el proyecto TestCtlDemo está todavía en modo de ejecución, haga clic en el botón Cerrar del Form1 para volver al modo de diseño. 2. En la ventana Explorador de proyectos, haga clic en ControlDemo para seleccionar el proyecto. 3. En el menú Archivo, haga clic en Generar ControlDemo.ocx para abrir el cuadro de diálogo Generar proyecto. Haga clic en Aceptar para generar el archivo .ocx. 4. En el menú Archivo, haga clic en Quitar proyecto para quitar ControlDemo del grupo de proyectos, de forma que Visual Basic utilice el componente binario compilado (archivo .ocx) en lugar del proyecto. Visual Basic muestra un mensaje de advertencia porque el proyecto TestCtlDemo contiene una referencia a ControlDemo. Haga clic en Sí para quitar ControlDemo de todos modos. Cuando quita ControlDemo del grupo de proyectos, Visual Basic busca ControlDemo.ocx en el Registro de Windows. Si existe el archivo .ocx, Visual Basic actualiza automáticamente la referencia que se ha establecido en el procedimiento "Agregar el proyecto TestCtlDemo". Para volver a usar el proyecto en lugar del componente binario, puede hacer clic en Agregar proyecto en el menú Archivo y agregar otra vez el proyecto ControlDemo al grupo de proyectos. 5. Presione F5 para ejecutar TestCtlDemo usando el archivo .ocx. Cuando ControlDemo se ejecuta desde el código fuente, no puede tener acceso al control ShapeLabel desde otras aplicaciones o desde otra instancia de Visual Basic. Esto se debe a que los componentes del control ActiveX tienen que ejecutarse en proceso. Una vez compilado el componente .ocx, puede probarlo desde otras aplicaciones. Para usar ControlDemo.ocx en otra instancia de Visual Basic
1. Abra una nueva instancia de Visual Basic. En el cuadro de diálogo Nuevo proyecto, haga doble clic en el icono EXE estándar para abrir un proyecto .exe. 2. En el menú Proyecto, haga clic en Componentes para abrir el cuadro de diálogo Componentes. En la ficha Controles, active ActiveX Control Creation Demo y haga clic en Aceptar.
Página:54 de 66
El icono para ShapeLabel aparece en el cuadro de herramientas. Ahora puede agregar controles ShapeLabel al formulario predeterminado y usar la ventana Propiedades para establecer sus propiedades. También puede hacer clic con el botón secundario del mouse en una instancia de ShapeLabel y elegir Propiedades en el menú contextual para modificar las propiedades del control con la página de propiedades. 3. Presione F5 para ejecutar el proyecto. También puede compilar el proyecto y ejecutar el archivo .exe.
Página:55 de 66
Temas de Programación Avanzada Acceder a la API de Windows La API de Windows, o Interfaz de Programación de Aplicaciones, es un conjunto de funciones que Windows expone a los programadores. Estas funciones del Sistema Operativo Windows pueden ser llamadas desde Visual Basic para realizar tareas que no se pueden programar mediante código estándar de Visual Basic. Por ejemplo, VB carece de funciones que reinicien la computadora. No obstante el reinicio se puede hacer a traves de una llamada a la API de Windows.
Comprender la API de Windows Desde el punto de vista del programador de Visual Basic, las funciones de la API de Windows son similares a las funciones “normales” de VB. Contienen parámetros de entrada y salida y
a veces un valor de retorno. Sin embargo, las funciones de la API ya están compiladas en un archivo separado, que se conoce como biblioteca de vínculos dinámicos (o DLL). Para usar estas funciones, hay que añadir unas cuantas lineas de codigo que definan en Visual Basic la función externa. En otras palabras, para usar una funcion de la API, en primer lugar hay que declararla. Las declaraciones de la API se introducen en la sección de declaraciones de un Módulo. Al igual que se declaran variables. La instrucción Declare enumera todos los parámetros de la función de la API, la DLL en la que esta ubicada y el tipo de datos del valor de retorno. Al contrario de lo que ocurre con una función de VB “normal” , una declaración de la API no tiene codigo de funcion. En lugar
de ello, la instrucción de línea única señala al archivo DLL que contiene la función.
Programa de Visual Basic Archivo Sistema
DLL
del
Lineas de declaración API
Código de Visual Basic
Utilización de la API de Windows en un ejemplo simple: Para demostrar el uso de la API desde Visual Basic, haremos un Proyecto .EXE Estándar 1. Inicie Visual Basic y cree un proyecto .EXE Estándar
Página:56 de 66
2. Agregue un Módulo, haciendo clic en la opción Agregar Módulo del Menú Proyecto 3. Vaya a la sección de declaraciones del Módulo 4. Haga Clic en el Menú Complementos y elija Administrador de Complementos y en la pantalla del Administrador marque las opciones como se muestra en la figura
Esto permitirá habilitar el Visor de API de VB6 para facilitar la declaración de las funciones de la API de Windows. Una vez hecho esto, haga clic en Aceptar 5. Nuevamente despliegue el menú Complementos y haga clic en la opción Visor de API
6. Aparece en pantalla el Visor de API 7. Haga clic en el menú Archivo y elija la opción Cargar Archivo de texto 8. En el cuadro de dialogo Abrir, marque el archivo WIN32API.txt y luego haga clic en Abrir 9. Una vez hecho esto el visor se cargara con los nombres de las funciones disponibles (ver imagen de la pagina siguiente)
Página:57 de 66
10. Busque la función llamada ExitWindowsEx y luego haga clic en el botón Agregar que está a mano derecha 11. Ahora haga clic en el botón Copiar (parte inferior derecha) 12. Regrese a la pantalla de Visual Basic y en la sección de declaraciones del modulo, use la combinación de tecla CTRL+V para pegar la declaración Como Podrá observar la declaración aparece de manera muy extensa y algo compleja, sin embargo en algunos casos es necesario completar esto con declaraciones de constantes referidas a la API elegida, debajo de la declaración de la función, agregue: Public Declare Function ExitWindowsEx Long, ByVal dwReserved As Long) As Long Public Public Public Public
Const Const Const Const
Lib
"user32"
(ByVal
uFlags
As
EWX_FORCE = 4 EWX_LOGOFF = 0 EWX_REBOOT = 2 EWX_SHUTDOWN = 1
13. Vaya a su formulario y agregue un botón de comando 14. en el evento clic de dicho botón coloque el siguiente código: Private Sub Command1_Click() Dim lRetVal As Long lRetVal = ExitWindowsEx(EWX_REBOOT, 0) End Sub
15. Guarde los cambios a su proyecto 16. Ejecute el formulario 17. Su computadora deberá estar reiniciándose
Página:58 de 66
Programación Cliente/Servidor en Visual Basic utilizando el Control WinSock Conceptos Básicos de Programación Cliente/Servidor Un programa simple es un conjunto de instrucciones que generalmente devuelven un valor al usuario, ya sea numérico o una cadena de letras, este dato es el resultado de la acción del usuario sobre el programa, ya que el usuario fue el que solicitó el dato. Al igual que un usuario se comunica con un programa por medio del teclado y dos personas se comunican por medio del teléfono, dos programas se pueden comunicar entre sí por medio de sockets. Visual Basic cuenta con un control especial que se denomina WinSock Control, el cual simplifica la programación de los sockets para ahorrarle tiempo al programador. Este control se encuentra bajo el nombre de archivo winsock.ocx, dicho nombre proviene de Windows Sockets. El Winsock Control como opción predeterminada no se encuentra disponible en la barra de controles estándar de Visual Basic, para acceder a él debemos agregarlo manualmente mediante Proyecto> Componentes> y luego seleccionar WinSock Control y Aceptar. No es visible en tiempo de ejecución, lo que significa que no podremos verlo mientras nuestra aplicación se este ejecutando, no obstante podemos modificar sus propiedades en tiempo de ejecución. Este tipo de aplicaciones Cliente-Servidor permiten comunicar programas entre sí y en consecuencia también permiten intercomunicar computadoras, porque habiendo un programa en la computadora llamada “Oscar_1” y otro en la computadora llamada “Daniel_1” ambos programas se pueden comunicar a través de Internet.
Para que el lector entienda por completo y de forma sencilla cuál es la estructura del software Cliente-Servidor vamos a dar un ejemplo bien sencillo y concreto. Un programa para administrar un cyber-café es un programa que se basa en la arquitectura ClienteServidor, permitiendo al dueño del local controlar/administrar las computadoras que posee. El dueño del local puede facturar el tiempo que se utilizó en cada computadora, apagar las computadoras, reiniciarlas, todo de forma ordenada y sin la necesidad de ir máquina por máquina. Como si esto no fuera poco además y por más increíble que parezca el dueño podría administrar el local desde su casa, a través de Internet, de la misma forma que lo haría si estuviese en el local, ya que el programa es el mismo, pero se utiliza a distancia gracias a la red Internet. Programas Troyanos
Un troyano es un aplicación “disfrazada” de un programa útil, consta de dos programas, el “Servidor” es el que se encarga de abrir un puerto en la PC a la que se quiere tener acceso y
dejar el puerto a la escucha, es decir, esperando a que se realice una conexión a dicho puerto para dar acceso a la máquina. Y el “Cliente” que es el programa que se conecta al
puerto que el Servidor dejó abierto, solicita que se realice la conexión y después comienza a transmitir información, solicitando datos de la PC remota, que pueden ser información del sistema, contraseñas, archivos importantes, etc. Se pueden utilizar de dos formas completamente distintas; Como herramienta de administración remota: que permite manipular el sistema a distancia, ideal para personas que necesitan urgente un archivo de la PC de su oficina y se encuentran en su casa. Se puede considerar como tal solo cuando el usuario tenga el acceso permitido a esa PC. •
Como herramienta para hackers: (hacking: penetrar un sistema informático sin acceso) esta es la forma de utilización que prefiere cualquier persona con una conexión a Internet y ganas de espiar lo que hace otra persona conectada a Internet o a su red privada, también llamada LAN (Local Area Network). Pudiendo acceder a sus archivos confidenciales, contraseñas, recursos compartidos, conversaciones que toman lugar en tiempo real, o borrar archivos fundamentales tales como por ejemplo: COMMAND.COM (dejando a la PC víctima sin poder arrancar, a menos que el usuario atacado sepa iniciar desde un disco de rescate/inicio). •
Página:59 de 66
Los puertos que se dejan a la escucha generalmente son muy altos, es decir puertos que pasan del número 20000, para garantizar que ningún otro programa pueda estar usándolos y cancelar la conexión del troyano. El uso de estos programas no es ilegal a menos que el usuario final opte por entrar a la máquina remota sin autorización. En dicho caso se puede proceder legalmente de acuerdo al país en el que se encuentre la PC hacheada/víctima, es decir la computadora a la que se infiltró el hacker (hacker: persona interesada en el funcionamiento y vulnerabilidad de los sistemas operativos, lenguajes de programación y seguridad informática). Por ejemplo en EEUU se puede condenar a una larga sentencia por hacer eso, pero también hay que conocer la otra cara de la moneda, es el caso de Argentina, donde todavía no esta tipificado en el código penal la intrusión en computadoras sin autorización, esto quiere decir que no es un delito condenable, a menos que en dicha intrusión se eliminen datos. Aquí debajo una lista de los troyanos más conocidos del Underground, es decir de la sociedad que ronda el hacker, o más bien todo aquello que sea difícil de encontrar para el usuario común. La palabra UnderGround significa debajo de la tierra, lo que para la mayoría significa algo oculto y qué otro ejemplo más conciso que los programas que usa un hacker. Cabe aclarar que el uso de estos programas comúnmente denominados “para hackers” no convierte a nadie pero absolutamente a nadie en “hacker”. No solo eso, sino que cualquier
persona que se jacte de usar estos programas se ganará el desprecio de los verdaderos hackers, quienes arduamente programan sus propios programas luego de haber estudiado años para hacerlo. El hacker no se hace de la noche a la mañana, es más, el hacker no se hace, nace… •
NetBus: Este “troyano” o “herramienta de administración remota” fue uno de los más
difundidos en Internet, ganó un gran número de usuarios adictos al programa por su sencillez de uso y la rapidez del mismo. El tamaño del servidor (el encargado de permitir el acceso a la máquina con o sin autorización) parece grande en comparación con el servidor de los troyanos actuales. Tamaño del servidor: 495 KB aproximadamente. Back Oriffice 2000: Sin lugar a duda el troyano que más pánico causó en los últimos tiempos. Fue el preferido de todos por ser el primero que salió en Internet con una facilidad de uso impresionante y características que otros troyanos aun no imaginaban, como la renovada parte gráfica entre otras cosas. En la última versión del programa se puede notar que fue programado para funciones de administración remota, ya que se nota la programación estructurada y concisa, sin botones de más, ni funciones innecesarias para el usuario final. •
SubSeven: Otro troyano que causó un gran impacto, probablemente el más usado en la actualidad, ya que el programa servidor ocupa menos aun que el servidor del NetBus o el Back Oriffice. La parte gráfica es distinta a las demás, la complementan un gran juego de •
“skins” (texturas, colores, etc.) y mejor facilidad de uso, además incluye nuevas funciones
como la desconexión de Internet del equipo remoto, el cuelgue del modem, el cambio de resolución de la pantalla, lista de los passwords que se encuentran en el cache (las contraseñas que el usuario escribió recientemente), y los passwords de la conexión telefónica a redes, es decir la contraseña de Internet si es que la víctima se conecta por teléfono. Tamaño del servidor: 327 KB Cybersensor: Este troyano esta programado especialmente para funcionar bajo WindowsNT. No es tan conocido como los anteriores. Tamaño del servidor: 29.5 KB •
DeepThroat v2: Este programa también es bastante conocido, incluye muchas funciones muy parecidas al resto de los troyanos, como la de adquirir las contraseñas en el chache de la PC remota y las típicas funciones que encontramos en el resto. Tamaño del servidor: 304 KB •
Dolly Trojan: Excelente troyano, lástima que no se ganó el aprecio del público porque el servidor es muy grande. •
Girlfriend 1.35: Al contrario del Dolly Troyan este programa es muy pequeño, al igual que su servidor, por lo tanto no incluye tantas funciones. •
Página:60 de 66
InCommand v1.0: Diferente a todos los demás este programa es de tamaño medio, pero lamentablemente no pudo adquirir la atención del usuario porque no tiene suficientes funciones. Tamaño del servidor: 168 KB •
NetSphere: Nuevamente, al igual que el Dolly este troyano posee un servidor muy grande por lo que se hace pesado el envío por Internet o por e-mail, lo que lleva a la gente a buscar una alternativa menos pesada para enviar, recurriendo a otro troyano. Tamaño del servidor: 621 KB •
•
Master Angel 97: Este troyano es uno de los menos conocidos.
Comenzando a Programar con el Control Winsock Protocolos TCP/IP y UDP Como anteriormente quedó aclarado dos programas se pueden conectar entre sí a través de internet o de una LAN. Internet usa el protocolo TCP/IP que significa “Transmision Control Protocol / Internet Protocol”, es el que se encarga de recibir paquetes de información y redirigirlos al usuario
final que los solicitó. Este protocolo es el preferido por todos ya que posee una característica que UDP le envidia, TCP/IP puede verificar que el paquete de información haya llegado con éxito al destinatario final, concretando así la transacción. Por el contrario UDP no puede hacer esto, solo manda el paquete con la información y no verifica que haya llegado satisfactoriamente, poniendo de esta manera en peligro al paquete, ya que puede no llegar entero al destinatario y por lo tanto no sirve si el paquete no llega en su totalidad. Todas las máquinas que están conectadas a Internet tienen asignadas una dirección IP que es única, ya que cada proveedor de servicios de Internet tiene asignado un rango de números IP para sus clientes. Los números IP estan compuestos por 4 grupos de 3 dígitos cada uno. Cada grupo no puede superar el númer 255. La máxima dirección que se puede formar es: 255.255.255.255
Propiedades, métodos y eventos de WinSock. Una vez que tenemos el WinSock control en nuestra barra de controles en Visual Basic podemos comenzar a ver las propiedades, eventos y métodos más importantes del control. Para agregarlo manualmente ir a Proyecto> Componentes> y luego seleccionar WinSock Control y Aceptar. Como mencionamos anteriormente este control no es visible en tiempo de ejecución. Primero abrimos un proyecto (EXE Estándar) y colocamos en control en cualquier parte del formulario. Vamos a comenzar por ver las propiedades, estas pueden ser establecidas en tiempo de diseño como también en tiempo de ejecución. A continuación se muetran las propiedades más importantes.
Lista de propiedades más importantes: LocalIP: Devuelve la dirección IP de la máquina local en el formato de cadena con puntos de dirección IP (xxx.xxx.xxx.xxx). LocalHostName: Devuelve el nombre de la máquina local. RemoteHost: Establece el equipo remoto al que se quiere solicitar la conexión. LocalPort: Establece el puerto que se quiere dejar a la escucha. RemotePort: Establece el número del puerto remoto al que se quiere conectar. State: Verifica si el Control WinSock esta siendo utilizado o no.
Página:61 de 66
Estas son algunas de las propiedades más importantes, y a continuación la sintaxis de cada propiedad. Objeto.Propiedad = Valor Donde Objeto va el nombre del Control WinSock, el nombre predeterminado cuando lo incluimos en alguna aplicación es “WinSock1”. Luego le sigue la propiedad que deseamos
asignar y finalmente el valor que la misma tomará.
Entonces por ejemplo si queremos probar la propiedad LocalIP debemos seguir el ejemplo 1.
Ejemplo 1 Crear un Proyecto (EXE Estándar) y agregar el WinSock Control. Luego agregar una etiqueta vacía, es decir un Label. Después introducimos el siguiente código. Private Sub Form_Load() Label1.caption = WinSock1.LocalIP End Sub
Este simple ejemplo nos muestra de forma rápida nuestro número IP. Si no estamos conectados a Internet nuestro número IP es 127.0.0.1 (es un número que se reserva la placa de red para pruebas internas). Podemos usar este número IP cuando queramos probar nuestras propias aplicaciones Cliente-Servidor sin tener que recurrir a otra computadora, es decir, ejecutar tanto el Server como el Cliente en una misma PC. Ahora que sabemos manejar las propiedades podemos seguir con los Métodos. A continuación la lista de algunos de los Métodos más importantes del Control WinSock.
Lista de Métodos más importantes Accept: Sólo para las aplicaciones de servidor TCP. Este método se utiliza para aceptar una conexión entrante cuando se está tratando un evento ConnectionRequest. GetData: Recupera el bloque actual de datos y lo almacena en una variable de tipo Variant. Listen: Crea un socket y lo establece a modo de escucha. SendData: Envía datos a un equipo remoto.
Lista de Eventos más importantes ConnectionRequest: Se produce cuando el equipo remoto solicita una conexión. Sin este evento no se puede llevar a cabo la conección. Connect: Se produce cuando el equipo local se conecta al equipo remoto y se establece una conexión. Close: Se produce cuando el equipo remoto cierra la conexión. Las aplicaciones deben usar el método Close para cerrar correctamente una conexión TCP. DataArrival: Se produce cuando llegan nuevos datos. Este evento es importante, ya que debemos hacer algo con la información que llega. La sintaxis de los métodos y eventos es igual a la sintaxis de las propiedades, por lo cual no vamos a hacer referencia a ella.
Programando la primera aplicación Cliente/Servidor.
Página:62 de 66
Conociendo las propiedades, métodos y eventos del Control WinSock podemos pasar a la engorrosa labor de la programación. Para poder programar la siguiente aplicación necesitan tener el Control WinSock en el formulario (no importa el lugar), asegúrese de tenerlo ya que es fundamental para que el programa funcione correctamente. Para entender el correcto funcionamiento del protocolo TCP/IP vamos a empezar por programar la aplicación Servidor a la cual luego se conectará el Cliente. Comenzamos por crear un proyecto nuevo (EXE estándar) para el Servidor, y agregamos la siguiente lista de controles al formulario principal. La ubicación de dichos controles es a gusto del programador, siempre tratando de que el usuario final este a gusto con el producto y que se pueda manejar libremente sin problemas por el entorno del mismo. o o o
WinSock Control 2 cajas de texto (Text Box) 2 botones (Command Button)
A continuación hace falta que cambiemos algunas propiedades de los controles, debajo la lista de controles con las respectivas propiedades a cambiar. Control (nombre predeterminado)
Propiedad (nuevo valor)
WinSock1 Text1 Text2 Command1 Command2
LocalPort = 888 Text = “” Text = “” Caption = “Escuchar” Caption = “Enviar”
Para orientar mucho mejor al programador que esta leyendo este tutorial incluimos imágenes del formulario para que se puedan guiar en caso de que lo necesiten, si no lo necesitan pueden ubicar los controles a su gusto.
Una vez hecho esto podemos empezar a tipear código. El sangrado del programa (espacio entre el código y el margen) es una cuestión de entendimiento/comprensión para el programador, algunos recurren a éste como otros no, eso también queda a criterio de la persona que programa. En el Evento Click del Command1 incluimos el siguiente código; (sólo lo que esta en negrita, el resto es en modo de ayuda, ya que aparece cuando se hace doble click en algún control). Private Sub Command1_Click() Winsock1.Listen
Página:63 de 66
End Sub Esto hace que el Control WinSock empiece a funcionar, escuchando el puerto que se indicó anteriormente en las propiedades de dicho control. Este puerto es el 888. Si seguimos los pasos anteriores correctamente entonces el puerto 888 esta siendo vigilado/escuchando para aceptar conexiones remotas. Luego en el Evento DataArrival del WinSock Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long) Dim datos As String Winsock1.GetData datos Text1.Text = Text1.Text + datos End Sub Datos queda transformada en una variable de cadena, y WinSock almacena la información que recibe del Cliente en el buffer (zona de memoria) y luego ingresan a la variable datos. Posteriormente el contenido de dicha variable (datos) se mostrará en el objeto TextBox1 (Text1). En el evento ConnectionRequest Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long) Winsock1.Close Winsock1.Accept requestID End Sub Este evento es muy importante, permite aceptar la petición de conexión. Sin este evento el resto del programa no tendría efecto. En el evento Click del command2 Private Sub Command2_Click() Dim enviar As String enviar = Text2.Text Winsock1.SendData enviar End Sub Esto permite enviar el texto que se introduzca en el TextBox2 (text2). Por ahora este es un simple programa Servidor, lo que hace es: designar un puerto, dejarlo a la escucha para aceptar conexiones, si se realiza una petición de conexión la acepta, y por último envía datos al Cliente y recibe los datos que éste envíe. Para seguir programando el Cliente hace falta crear un nuevo proyecto y en el formulario principal incluir la siguiente lista de controles: o o o
WinSock Control 3 cajas de texto (Text Box) 2 botones (Command Button)
Como lo hicimos anteriormente hace falta cambiar algunas propiedades. Debajo la lista de controles con las respectivas propiedades para cambiar.
Control (nombre predeterminado)
Propiedad (nuevo valor)
WinSock1 Text1
RemotePort = 888 Text =
Página:64 de 66
Text2 Text3 Command1 Command2
Text = Text = Caption = “Conectar” Caption = “Enviar”
Para tener una referencia de cómo situar los controles conviene seguir la Figura siguiente
En el evento del command1 Private Sub Command1_Click() Winsock1.RemoteHost = Text3.Text Winsock1.Connect End Sub El evento Connect nos permite conectarnos al programa servidor que esta esperando nuestra solicitud. Este evento requiere un parámetro fundamental, el número IP o nombre de host, el cual es introducido previamente a la conexión en TextBox3 (Text3). En el evento DataArrival del WinSock Control Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long) Dim datos As String Winsock1.GetData datos Text1.Text = Text1.Text + datos End Sub Esto permite a la aplicación (a través de WinSock) recibir información del servidor y mostrarla en pantalla. En el método del command2; Private Sub Command2_Click() Dim enviar As String enviar = Text2.Text Winsock1.SendData enviar End Sub Estas instrucciones son necesarias para enviar información al servidor.
Página:65 de 66