| Artículos | 01 JUN 2001

¿Punteros en Visual Basic?(I)

Tags: Histórico
José M. Alarcón.
Al contrario de lo que mucha gente piensa, Visual Basic sí soporta el uso de punteros. Cuando se le cuenta a algunos programadores de C, no se lo creen. En esta serie de artículos aprenderá a utilizarlos en su código para conseguir cosas que antes creía imposibles o para llevar a cabo procesos a una velocidad normalmente impensable en VB.

Antes de nada un aviso para los lectores: los temas que trataremos en esta serie de artículos son muy avanzados para el programador medio de VB. Para seguirlos con normalidad deberá tener un buen conocimiento de Visual Basic, entender a la perfección cómo funcionan las variables, la memoria del ordenador, los tipos definidos por el usuario, las declaraciones de la API y, sobre todo, no deberá tener miedo a provocar excepciones en su sistema cuando experimente.

Limitaciones de Visual Basic
En esencia, un puntero es una dirección de memoria que contiene datos brutos en los que estamos interesados. Los punteros son muy importantes en lenguajes como C y C++ porque permiten la manipulación directa de la memoria del ordenador, con la flexibilidad y potencia que ello conlleva. Pero al mismo tiempo, esta libertad de actuación los convierte en una herramienta peligrosa si se manejan mal.
Una de las cuestiones que más se le ha achacado a VB es la carencia de funciones para manejo de punteros para acceso directo a la manipulación de la memoria. Otros lenguajes RAD como Delphi, por ejemplo, poseen soporte nativo y simple para ello, pero no VB. Como dijo Bill Gates en cierta ocasión: “Cuando Basic soporte punteros dejará de ser Basic”. El resultado de esta afirmación es que VB oficialmente no soporta el uso de punteros, pero realmente sí lo hace. Veamos cómo se digiere esta afirmación.

Direcciones de funciones
Oficialmente, la única función que posee VB para manejar asuntos relacionados con la memoria es AddressOf. Ésta toma como argumento el nombre de una función o método y devuelve su dirección de memoria. Existen algunas limitaciones motivadas por las complicaciones que podría suponer un mal uso de la información que devuelve.
Por ejemplo, sólo puede usarse como parámetro en la llamada de una función, siendo “imposible” guardar la dirección de una función en una variable, es decir, si intenta hacer lo siguiente:
Dim miFuncDir As Long
MiFuncDir = AddressOf(MiFuncion)
obtendrá un error. Sin embargo, esto es muy fácil de eludir definiendo una función similar a la siguiente:
Public Function FuncDir(Direccion As Long) As Long
FuncDir = Direccion
End Function
De esta forma, puede guardar la dirección de una función en una variable con tan sólo escribir:
Dim miDir As Long
MiDir = FuncDir(AddressOf MiFuncion)
Como se ve, algo muy sencillo.
Otra limitación de AddressOf es que solamente se puede utilizar con métodos que residan en un módulo estándar de código (o sea, un .bas), siendo imposible obtener la dirección de un método de un objeto COM. Esto es importante sobre todo a la hora de diseñar componentes y objetos COM, pero no es algo que nos deba quitar el sueño.
Las aplicaciones típicas de AddressOf son la subclasificación de ventanas y controles (que contaremos en otros artículos si los lectores así lo desean) y funciones de retrollamada (Callback). En general, en cualquier situación que requiera conocer la dirección de un método para que éste pueda ser llamado por el sistema. Es una lástima que VB no incorpore alguna manera de ejecutar una función a partir de su dirección de memoria, ya que abriría un importante abanico de posibilidades.
No nos extenderemos más en los aspectos de AddressOf, puesto que se trata de una función documentada (mire en la ayuda de VB5 o VB6), y nosotros estamos interesados en los secretos del lenguaje.

Vamos a ponernos serios
Aparte de AddressOf no existen más posibilidades de tratar con posiciones de memoria en Visual Basic, al menos ateniéndose a la documentación. La realidad es que, ocultas en algún lugar de su biblioteca de tiempo de ejecución, existen tres funciones que permiten obtener punteros a variables: VarPtr, StrPtr y ObjPtr.
Estas funciones no están documentadas, y aunque use el examinador de objetos de VB, no las podrá encontrar. Sin embargo, si escribe en el editor de código el nombre de una de ellas verá que Intellisense entra en acción y ofrece sus parámetros, lo cual quiere decir que sí existen. ¿Qué ocurre aquí?
La respuesta es que se trata de funciones ocultas. Hay varias de ellas en Visual Basic. Para llegar a verlas en el examinador de objetos (pulse F2 para mostrarlo) sólo tiene que pulsar con el botón secundario sobre el panel derecho de éste y escoger la opción Ver miembros ocultos. Al hacerlo, si selecciona la biblioteca de clases VBA, verá que existe una clase oculta llamada _HiddenModule (fíjese en el subrayado inicial), y dentro de ella las tres funciones que se acaban de nombrar, tal y como muestra la Figura 1.
A continuación se expone brevemente la utilidad de las tres funciones:
• VarPtr: obtiene un puntero a una variable cualquiera que se le pase. ¡OJO! El puntero es la dirección de la memoria donde apunta la variable, que no tiene por qué coincidir necesariamente con la dirección del verdadero contenido de ésta. En breve se explicará mejor el concepto de indirección, necesario para comprender la frase anterior.
• StrPtr: devuelve la dirección de memoria donde se encuentra el contenido de la cadena de texto referenciada por la variable que se le pase como argumento. De nuevo esté atento al significado de esta afirmación, un tanto liosa, que entenderá más adelante.
• ObjPtr: esta función toma como argumento una variable que referencia a un objeto y devuelve un puntero a la interfaz de éste.

Indirección
Para entender bien cómo trabajan estas funciones y las diferencias que existen entre ellas hay que comprender cómo almacena internamente los datos Visual Basic, es decir, cómo estructura la memoria para guardar los contenidos de las variables. Básicamente se puede decir que hay dos tipos de variables en VB: las de asignación directa y las de asignación indirecta.
Las primeras son las más simples y apuntan directamente a la dirección de memoria donde se guarda la información. Dentro de esta categoría se encuentran todos los tipos numéricos simples (Integer, Long, Double, Currency, etc..) y los tipos definidos por el usuario (TDU). Obteniendo un puntero a una de estas variables podremos manipular su contenido sin problemas.
Las variables de asignación indirecta contienen un puntero a otro puntero, que marca dónde residen realmente los datos. En este segundo tipo se encuentran los objetos, las cadenas de texto y las matrices de VB.
La forma de guardar la información que tienen estos dos tipos de variables es lo que en C++ se conocería como indirección simple e indirección múltiple respectivamente.
Enseguida nos ocuparemos del caso complicado, el de la indirección múltiple, viéndolo para cada tipo de objeto, pero mientras veamos el algo menos interesante (aunque importante) uso de los punteros a variables de asignación directa.

Punteros a variables simples y tipos definidos por el usuario
Antes de nada, conviene definir una función que convertirá en algo útil el hecho de disponer de un punt

Contenidos recomendados...

Comentar
Para comentar, es necesario iniciar sesión
Se muestran 0 comentarios
X

Uso de cookies

Esta web utiliza cookies técnicas, de personalización y análisis, propias y de terceros, para facilitarle la navegación de forma anónima y analizar estadísticas del uso de la web. Consideramos que si continúa navegando, acepta su uso. Obtener más información