Técnicas profesionales
avanzadas
Visual Basic permite crear aplicaciones empleando
una interfaz de múltiples documentos (MDI - Multiple Document Interface),
o dicho en términos de Visual Basic, múltiples formularios. En una aplicación
MDI, se pueden abrir varias ventanas hijas. Cada una de estas ventanas hijas
(formularios) son iguales entre sí. En una aplicación MDI pueden haber varias
ventanas hijas, pero solo una ventana padre por aplicación. El formulario padre
actúa como contenedor de los formulario hijo. Muchos procesadores de textos
bajo Windows son buenos ejemplos de aplicaciones MDI.
Para crear una aplicación MDI se empezará a crear
un nuevo proyecto y, se accede a Insert/MDI Form. El nuevo
formulario será el formulario padre. Para que un formulario sea un formulario
hijo, se deberá cambiar su propiedad MDIChild y establecerla a True.
Cuando se visualizan varios formulario hijos,
todos comparten el mismo código, pero cada uno de ellos guarda sus propios
datos y reconoce sus propios sucesos. Según ésto, no se podrá utilizar el
identificador del formulario para referirse a los controles o a sus
propiedades, aunque sí se podrá utilizar la palabra clave Me.
Los únicos controles que se pueden incluir en un formulario padre son aquellos que tengan la propiedad Align y, dentro de éstos controles se podrán colocar otros controles. De esta forma se crean las barras de herramientas.
Los menús de cada formulario hijo, son visualizados en el formulario padre.
Cada vez que se activa un formulario hijo, su menú sustituye al menú que se
esté visualizando en el formulario padre. Ahora bien, si no hay un formulario hijo
cargado, o si dicho formulario no tiene menú, entonces se visualiza el del
padre, si lo tiene.
Es aconsejable que el formulario padre tenga un menú que permita abrir o
crear un nuevo formulario hijo.
EVENTO QUERYUNLOAD
Cuando el usuario ejecuta la orden Cerrar del menú de control del formulario
padre, Visual Basic intenta descargar dicho formulario. Esto hace que se dé el
suceso QueryUnload primero para el formulario padre y luego para cada uno de
los hijos.
Cuando el usuario ejecuta la orden Cerrar del menú de control del formulario
hijo también se da el suceso QueryUnload pero solo para este formulario.
La sentencia Unload permite descargar un formulario o un control de la
memoria, pero antes de que el formulario sea descargado, se da el suceso QueryUnload,
seguido del suceso Unload. El suceso QueryUnload para un formulario MDI va
seguido del suceso QueryUnload para cada uno de los formularios hijo.
EJEMPLO:
Vamos a construir una aplicación que permita
crear varios formularios hijo. Para ello, se necesitará crear un nuevo proyecto
con un formulario MDI y, un formulario hijo, al que se le haya establecido su
propiedad Caption a Formulario Hijo y su propiedad Name a frmHijo. Al
formulario padre se le añadirá un menú Archivo con los comandos Nuevo y Salir.
Se añadirá el menú Ventana con la propiedad Window List activada y, con las
opciones Cascada, Mosaico y Organizar iconos. También se le añadirá un control
3D panel, seleccionando Tools/Custom Controls. A dicho control se le modificará
las propiedades Align con 2 - Align Bottom, BevelInner con 1 - Inset, BevelWidth
con 2 y, BordeWidth con 2. Dentro de este control se añadirán dos etiquetas:
lblTexto y lblContador.
¿Qué es el API Win32 ?
Código
|
| En un nuevo módulo:
Public Contador As Integer
En el formulario padre:
Private Sub mnuArchivoNuevo_Click()
Dim X As New frmHijo
Contador = Contador + 1
X.Show
End Sub
Private Sub mnuArchivoSalir_Click()
End
End Sub
Private Sub mnuVentanaCascada_Click()
MDIForm1.Arrange 0
End Sub
Private Sub mnuVentanaMosaico_Click()
End Sub
Private Sub mnuVentanaOrganizar_Click()
MDIFomr1.Arrange 3
End Sub
Private Sub MDIForm_Initialize()
Contador = 0
lblContador = Str(Contador)
End Sub
En el formulario hijo:
MDIForm1.lblContador = Str(Contador)
End Sub
Private Sub Form_Unload(Cancel As Integer)
‘Si el valor de Cancel es True, el formulario asociado no se descarga.
‘En otro caso, se van cerrando primero cada hijo y, por último el padre.
Contador = Contador - 1
MDIForm1.lblContador = Str(Contador)
|
¿Qué es el API Win32 ?
Win32 es un conjunto de funciones, tipos y mensajes
pre-definidos para poder programar sobre los sistemas operativos de 32 bits de
Microsoft. El API Win32, surge para cubrir la necesidad de crear un sistema
operativo de 32 bits como es Windows 95, frente al API de 16 bits existente de
Windows 3.1. Surge el problema de que Win32, no es compatible con el API de 16
bits, lo que implica que si queremos portar un código de Windows 3.1 a Windows
95, deberemos reescribir el código. Aunque hemos dicho que el API Win32 no es
compatible con el API de 16 bits, hay una versión que es Win32s que sirve para
la versión 3.1 de Windows. Algunas de las limita- ciones entre ambos API son:
No
soportan nombres de ficheros largos, sólo el conocido formato 8.3 de DOS.
No
tiene API de comunicaciones.
No
soportan las capacidades Plug & Play.
Llamadas a las
Funciones del API de Windows
Un programador de aplicaciones Windows además de
conocer el entorno de trabajo de Windows debe conocer también su entorno de
programación, conocido generalmente como interfaz de programación de
aplicaciones de Windows ( Windows Application Programming Interface,
abreviadamente Windows API ).
La característica primaria de la API de Windows son
las funciones y los mensajes internos/externos de
Windows.
Las funciones Windows son el corazón de las
aplicaciones Windows. Hay más de 600 funciones de Windows dispuestas para ser
llamadas por cualquier lenguaje, como C o Visual Basic.
A través de estos mecanismos, podemos realizar gran
cantidad de funciones que hasta el momento no teníamos ni idea que se podían
realizar. La utilización de ésta serie de librerías que contienen las funciones
de la API pueden solucionar gran cantidad de problemas en la programación,
aunque también no debemos desestimar el gran poder destructivo de las mismas.
La depuración de un programa es muy diferente si éste tiene incorporadas
llamadas a APIs, ya que el resultado de las mismas en algunos casos puede
llegar a ser incomprensible. Cuando se trabaja con éstas funciones siempre es
recomendable tener a mano una buena guía o bien tener a mano alguien que sepa,
para no encontrarnos con posibles problemas.
Las dos principales ventajas que obtenemos con la
utilización de APIs es la gran funcionalidad que podemos darle a nuestra
aplicación, y en segundo lugar la gran velocidad de proceso, ya que a menudo es
mucho más rápido realizar una función a través de la API adecuada que por medio
del lenguaje en si mismo.
Los mensajes son utilizados por Windows para permitir
que dos o más aplicaciones se comuniquen entre sí y con el propio sistema
Windows. Se dice que las aplicaciones Windows son conducidas por mensajes o sucesos.
Conocer todas las APIs de Windows es imposible, ya que
tiene gran similitud con aprenderse la guía de teléfonos.
Lo que debemos hacer es realizar un razonamiento
contrario, nosotros tenemos una necesidad a la hora de programar, y debemos
pensar que eso tiene una solución con una API.. En la mayoría de los casos es
así.
Librerías
Dinámicas.
Casi todas las APIs de Windows se unen formando
librerías de enlace dinámico.
Una librería dinámica ( Dynamic Link Libraries,
abreviadamente DLLs ) permite que las aplicaciones Windows compartan código y
recursos. Una DLL es actualmente un fichero ejecutable que contiene funciones de Windows que pueden ser
utilizadas por todas las aplicaciones.
Si bien en DOS estamos acostumbrados a utilizar
librerías de enlace estático, es decir, a la hora de compilar incluyen junto
con nuestro código, y de esta manera cuando se ejecuta nuestra aplicación,
todas las librerías se cargan en memoria esperando a ser invocadas. Sin
embargo, cuando trabajamos con DDLs, el enlace con la aplicación es dinámico en
tiempo de ejecución.
Una DDL no se incluye dentro de nuestro código, sino
que en el momento que realizamos la llamada a la función, la DLL se carga en
memoria, se utiliza la API, y a continuación se descarga.
La gran ventaja que posee este método es que no es
necesario tener gran cantidad de código cargado en memoria a la hora de
ejecutar nuestra aplicación. En contra, es necesario que cuando llevemos
nuestro ejecutable a otra instalación, tengamos que llevar las DLLs necesarias.
También tenemos que pensar que si utilizamos las DLLS
que nos proporciona Windows, en cualquier máquina con este sistema operativo
vamos a encontrar esas mismas DLLs, con lo cual no es necesario que nos las
llevemos.
La utilización de librerías dinámicas tiene ventajas.
Una ventaja es que como están separadas del programa se pueden actualizar sin
tener que modificar los programas que las utilizan. Otra ventaja es el ahorro
de memoria principal y de disco ya que como es Windows quien administra la
utilización de las DLLs, no existe duplicidad de código cuando varias
aplicaciones las utilizan.
También, como todo (jeje) tiene inconvenientes. Uno de
ellos es el tiempo que Windows tiene que emplear en leer las funciones que el
programa necesita utilizar de una DLL.
Otra desventaja
es que cada programa ejecutable necesita que estén presentes las DLLs que
utiliza. Cuando se utilizan librerías
estáticas, las funciones que el programa necesita se incluyen en el mismo, por
lo que ni se pierde tiempo en leerlas ni la librería tiene que estar presente. La mayoría de éstas librerías suelen estar
localizadas en el directorio SYSTEM de Windows. Dentro de Windows tenemos gran cantidad de
DLLs, agrupando las APIs en funciones respecto a un mismo tema. Además en cada
nueva versión de Windows, posiblemente tengamos más DLLs para utilizar.
Para acceder a las funciones de las librerías
dinámicas, lo primero que debemos hacer es declararlas.
Declaración de una Función DLL. Para declarar una
función de una librería dinámica, tiene que escribir una sentencia declare en
el módulo global de la aplicación, o en la sección de declaraciones de la forma
o del módulo correspondiente. Por ejemplo:
Declare Function
lopen Lib "kernel" Alias "_lopen" (Byval lpPathname as
string, Byval iReadWrite As Integer) as Integer. La
cláusula Lib indica al lenguaje de programación la librería donde puede
encontrar la función de la API de Windows declarada. Las DLLs del entorno
operativo están en "Kernel", "GDI", "User", o en
una de las DLLs correspondientes a un driver de dispositivo tal como
"Sound". Para otras DLLs, el nombre incluye el camino completo. Por ejemplo:
"c:windowssystemlzexpand.dll"
La cláusula alias indica que la función tiene otro
nombre en la librería dinámica ( DLL ). Esto es útil cuando el nombre de la función coincide con
alguna palabra clave, con alguna variable o constante global, o el nombre de la
función DLL, tiene caracteres no reconocidos por el lenguaje de programación.
La sentencia declare debe contener asimismo una lista de los parámetros que se
pasarán a la función. La mayor parte del trabajo consiste en determinar cuáles
serán esos parámetros. Algo muy utilizado dentro de los parámetros son lo que
podemos traducir como manejadores ( handles ). Esto es un valor entero único
definido por el entorno operativo y utilizado para referirse a objetos tales
como formularios, controles, etc. Un handle es un número de identificación.
HWnd es un handle para referirse a una ventana, hDC es un handle para referirse
al contexto de dispositivo de un objeto ( Device Context ). Cuando una función
de una DLL espera recibir como argumento un handle, se debe declarar como ByVal
Integer.
Declare Function IsIconic Lib
"User" (ByVal hWnd As Integer) As Integer
If IsIconic (Form1.hWnd) Then ....
El entorno operativo asigna un handle a cada
formulario de una aplicación para posteriormente identificarles. La propiedad hWnd de un formulario o de
un control no gráfico permite acceder a este handle. Por contexto de
dispositivo se entiende un conjunto de atributos (color de fondo, tipo de
letra, espaciado entre caracteres, posición actual de la pluma, paleta de
colores, etc.) que determinan la localización y la apariencia de un objeto. Una
aplicación puede modificar estas propiedades a través del hDC del objeto.
Afortunadamente, Microsoft ha pensado en el
programador y proporciona una herramienta dentro de algunos lenguajes de programación de entorno
visual como es el API viewer, en Visual Basic versión 4.0. Con ésta herramienta podemos cargar unos
archivos TXT que nos proporcionan las sentencias declare de gran cantidad de funciones API. Si no poseemos
ningún tipo de ayuda respecto a una API específica, es muy Posible que todos
nuestros intentos en utilizarla sean inútiles.
Para declarar una función de una librería dinámica, se
tiene que escribir en la sección de declaraciones de un formulario o de un
módulo de la aplicación en construcción. Una función declarada en un formulario
es privada para este formulario, y declarada en un módulo es pública, y por lo
tanto puede ser llamada desde cualquier parte de la aplicación.
Si la función no retorna un valor, se declarará como
un procedimiento o sub, aunque esta opción no se utiliza casi nunca, pues la
mayoría de las APIs retornan un valor, aunque sea una verificación de su
realización.
Los argumentos que se pasan a una función pueden ser
pasados por valor o por referencia. UN parámetro por valor quiere decir que lo
que estamos metiendo dentro de la función es el contenido de la variable,
mientras que por referencia se introduce la dirección de memoria donde reside
la variable que contiene el valor que queremos pasar.
Habitualmente, dentro de nuestro programa trabajamos
con variables que se pasan por valor, es decir, no nos interesa la posición de
memoria de la variable, sino su contenido. Al trabajar con APIs la cosa cambia.
La mayoría de estas funciones están desarrolladas en C, y en este lenguaje se
utiliza asiduamente los punteros (direcciones de memoria)
Por defecto, los lenguajes actuales de entorno visual
pasa los argumentos por referencia (Utilizando direcciones de 32 bits ).
Para pasar un argumento por valor, se debe de escribir
la palabra clave ByVal delante de la declaración del argumento.
Algunas funciones aceptan más de un tipo de datos para
un mismo argumento, y esto se indica declarando el argumento como Any.
Declare Function Catch Lib "Kernel"
(lpCatchBuf As Any) As Integer
Esta
función puede ser llamada con un argumento tipo cadena, de tipo largo, etc.
Algunas
Funciones de la API.
API
|
- Funciones de direccionamiento de
memoria a 32 bits.
Recupera el API para
aplicaciones que utilizan 32 bits.
- Funciones de ejecución de
aplicaciones.
Tiene la función de
cargar y ejecutar aplicaciones.
ej: Winhelp
Loadmodule
- Funciones bitmap.
Crea y maneja los bitmaps.
Createbitmap, crea un
bitmap.
Getpixel, recupera el color RGB del pixel
especificado.
- Funciones callback o rellamada.
Recupera información
sobre algo que se está ejecutando, con la posibilidad de hacer algún cambio.
Abortproc, procesa
los trabajos de impresora cancelados.
EnumFontFamProc,
recupera información sobre las fuentes (tipo de letra)
disponibles.
- Funciones de cuadro de diálogo
común.
Funciones que actúan
sobre una caja de diálogo común, cambiando su color, texto, etc.
Choosecolor, crea una
caja de diálogo seleccionando el color.
- Funciones de comunicación.
Funciones que
gestionan los dispositivos de comunicaciones.
Opencomm, abre un
dispositivo de comunicaciones.
- Funciones de cursor.
Gestionan todo lo
relacionado con el cursor.
Createcursor, crea un
cursor con dimensiones especificadas.
- Funciones DDE (Data Dinamic
Exchange ).
Gestiona el
intercambio de datos dinámico.
DdeAccessData,
proporciona un acceso a un objeto con memoria global.
DdeGetdata, copia los
datos de un objeto de memoria global a un buffer.
- Funciones de error.
Funciones que
gestionan los errores de los dispositivos.
Debugoutput, envía
mensajes al terminal erróneo.
- Funciones de movimiento y
visualización.
Isiconic, determina
si una ventana está minimizada.
- Funciones para las propiedades.
Informa y modifica el estado de
las propiedades.
Getprop, devuelve una
lista de propiedades de una ventana.
- Funciones pen.
Son las funciones
correspondientes al lápiz.
- Funciones de paleta de colores.
- Funciones de dibujo y pintura.
- Grupo de funciones OLE.
Funciones que se basan
en el manejo de objetos.
Olenumobjects, enumera
los objetos en un documento.
- Funciones Toolhelp.
Normalmente devuelven
información sobre los objetos que hay en memoria.
- Funciones Drag & Drop
Funciones de arratrar y
soltar.
Tiene información sobre la
posición de arrastre de algún elemento, si se puede arrastrar, etc.
- Funciones de controladores
instalables.
Hacen una gestión de los
controladores instalables.
- Funciones de decodificación
LEMPEL-ZIV.
Hacen una gestión de los
ficheros comprimidos.
- Funciones para la impresión.
Devuelve tamaños de
letra, página, etc. y activa o desactiva algunas funciones,
configura colores, etc.
a la hora de imprimir.
- Funciones SHELL (entorno).
Son las funciones que
controlan el entorno.
FindExecutable: recupera
el nombre del ejecutable asociado a un fichero especificado.
- Funciones "Stress"
Controla espacio libre y
manejadores de ficheros (handles).
AllocDiskSpace: crea un
fichero del espacio consumido en una partición del disco (instalar
software).
- Funciones TrueType
Funciones que controlan
los fuentes o tipos de letra a utilizar.
GetRasterizarCaps:
recupera el estado del tipo de letra en un sistema. Cuando
se hace un cambio de
tipo de letra ,
reestablece el que hay por defecto.
- Funciones de versión.
Función que controla la
versión de los ficheros.
GetfileVersionInfo:
devuelve información sobre un fichero especificado.
- Funciones GDI.
Controla todo lo que se
refiere a los gráficos, ya sea tipos de letra, manejo
de trabajo a la hora de una
impresión, prepara la
impresora para aceptar datos, etc.
StartPage: Prepara un
controlador de impresora para aceptar datos.
StarDoc: Inicializará un
trabajo de impresión.
GetRasterizerCaps:
recupera el estado del tipo de letra de un sistema.
- Funciones KERNEL.
Lleva a cabo una E/S a
ficheros, control de errores,etc.
hread: Lee datos de un
fichero.
hwrite: escribe datos en
un fichero.
Debugoutput: envía
mensajes a un terminal erróneo.
- Funciones de usuario.
Son funciones en las que
el usuario realiza alguna acción, como activar o desactivar flechas de scrollbar
(texto horizontal-vetical), recupera información de mensajes de
hardware, etc.
GetDriverInfo: recupera
datos de un dispositivo instalable.
CopyIcon: copia un icono.
OpenDriver: abre un
dispositivo instalable.
|
Una
de las primeras funciones que vamos a comentar es bastante utilizada.
En muchas ocasiones hemos querido saber qué resolución
tiene la pantalla de la pc en el momento que se ejecuta nuestro software. Con
ésta información podemos dar un aspecto bastante más profesional a nuestra
aplicación si ajustamos el tamaño de nuestros formularios a la resolución de la
pantalla. También a través de
la misma API sabemos la cantidad de puntos que nos da
la impresora, con lo que podemos ajustar nuestros informes independientemente
de la impresora seleccionada. Esta función la tenemos dentro de la librería
GDI,
y se denomina GetDeviceCaps. Dependiendo del valor del
índice introducido, así nos da la información sobre la cantidad de puntos
horizontales de la pantalla, cantidad de puntos verticales de la pantalla,
puntos por pulgada horizontalmente en la impresora y puntos por pulgada
verticalmente en la impresora.
Código
|
Declare Function
GetDeviceCaps Lib "GDI" ( ByVal HDC As_ Integer, Byval nIndex As
Integer) As Integer
Global
Const HorRes = 8 ' resolución horizontal en pixels
Global
Const VerRes = 10 ' resolución vertical en pixels
Global
Const PPPX = 88 ' pixels por pulgada en X
Global
Const PPPY = 90 ' pixels por pulgada en Y
Private Sub Command1_click()
p1 = GetDeviceCaps ( HDC, HorRes )
p2 = GetDeviceCaps ( HDC, VerRes )
i1 = GetDeviceCaps ( Printer, HDC, PPPX )
i2 = GetDeviceCaps ( Printer, HDC, PPPY )
Label1.Caption
= "Pantalla: " & p1 & " x" & p2
Label2.Caption = "Impresora: "
& i1 & " x " & i2
End
Sub
|
En muchas ocasiones necesitamos conocer dónde esta el
directorio de Windows y dónde reside el directorio System del mismo. Es muy
lógico suponer que todas las instalaciones están en el directorio C:Windows.
Puede ser que se ejecute desde una red, o que el
usuario haya cambiado el directorio por omisión. En cualquiera de estos casos
no podemos referirnos directamente a estos directorios, sino que debemos
conocerlos dinámicamente cuando ejecutamos la aplicación.
Para ello utilizamos dos APIs de la librería Kernel,
la primera nos devuelve el directorio de Windows
(GetWindowsDirectory ), mientras que la segunda el
directorio de System ( GetSystemDirectory ).
Para hacer funcionar esta API debemos inicializar la
variable que nos devuelve la información, con 255 caracteres rellenos con el
valor ASCII 0. Si la cadena estuviese vacía, no funcionaría, y su
comportamiento sería impredecible.
Código
|
Declare Function
GetWindowsDirectory Lib "Kernel " (ByVal_ lpBuffer As String, ByVal
nSize As Integer
Declare Function
GetSystemDirectory Lib "Kernel" (ByVal lpBuffer_ As String, ByVal
nSize As Integer
Private Sub Command2_Click
()
Dim Camino As String
Camino
= String( 255, 0 )
w = GetWindowsDirectory ( Camino,
Len(camino))
Label3.Caption = Camino
w = GetSystemDirectory ( Camino,
Len(Camino))
Label4.Caption = Camino
End
Sub
|
Algunas
Funciones Interesantes y una breve descripcion DDE cada una:
DDE
|
GetUserName
(Devuelve en nombre del usuario)
GetComputerName
(Devuelve en nombre del computador)
GetDiskFreeSpace
(Devuelve información sobre el disco duro)
GetDiskFreeSpaceEx
(Devuelve la capacidad de un disco mayor de 2Mb.)
GetVolumeInformation
(Nombre del Disco, tipo de formato y numero de disco)
GetLogicalDriveStrings
(Devuelve las unidades disponibles en un ordenador)
GetLocalTime
(Devuelve la fecha y hora del ordenador)
GetCursorPos
(Devuelve la posición del cursor en la pantalla)
GetDriveType
(Devuelve el tipo de Unidad)
SetWindowPos
(Formulario Siempre Visible)
GlobalMemoryStatus
(Información sobre la memoria fisica disponible)
ShellExecute
(Ejecutar)
GetVersionEx
(Devuelve la versión del Windows)
SystemParametersInfo
(Cambia el fondo de pantalla del Windows)
SHFileOperation
(Enviar un archivo a la papelera de reciclaje)
GetWindowsDirectory
(Mustra la ruta del Windows)
GetSystemDirectory
(Mustra la ruta del directorio System de Windows)
sndPlaySound
(Ejecutar sonidos .WAV)
FindExecutable
(Busca el archivo ejecutable asociado a un archivo, y muestra el icono)
GetKeyboardStateByString
- SetKeyboardStateByString (Seleccionar y Deseleccionar el Bloque Numerico
del teclado)
FindWindow
(Indica si una aplicación determinada esta en ejecución)
SystemParametersInfo
(Activa/Desactiva las teclas de Escape - CTRL+ALT+SUB - ALT+TAB - CRTL+ESC)
GetSysColor
(Devuelve los colores del Windows)
GetACP
(Determina la página de código ANSI vigente)
SetWindowPos
(Esconder y mostrar la barra de tareas del Windows)
ExitWindowsEx
(Apaga o Reinicia el Windows 95/98)
GetSystemInfo
(Información sobre el Hardware)
|
No hay comentarios:
Publicar un comentario