Nemesis_0
Usuario (México)
Índice de contenido Sumario 1 - Introducción 2 - Breve resumen de C++ (Diferencias con VB) 2.1 Conceptos generales de C++ 2.2 Variables 2.2.1 Tipos de variables 2.2.2 Modificadores 2.2.3 Punteros 2.2.4 Matrices 2.2.5 Estructuras y Clases 2.2.6 Variables públicas 3 Primera interacción entre VB y C++ 3.1 Nuestro primer programa 3.1.1 La librería Dll 3.1.2 La interacción con VB 4. Pasajes más complejos entre VB y C++ 4.1 Pasaje de matrices 4.3 Pasaje de variables String 5 Depuración de las librerías Dll 5.1 Depurando con mensajes ANEXO: Respuesta a los ejercicios Respuesta ejercicio 1 Respuesta ejercicio 2 Respuesta ejercicio 3 Esta documentación fue escrita con el propósito que le sea de utilidad, pero no tiene ningún tipo de garantía. La misma está sujeta a los términos de la Licencia de Documentación Libre GNU (www.gnu.org). Si el lector encuentra algún error (conceptual, gramatical, ortográfico, en el código, etc...), desea que explaye más un tema o quiere que incluya algún apartado más, le ruego me escriba a: lamalfa@gmail.com (también serán muy bienvenidas todas las críticas que el lector tenga del tutorial sean estas buenas... o de las otras ;-) ). Sumario Este tutorial se verá cómo se puede aumentar el rendimiento de los programas hechos en Visual Basic (en adelante VB) mediante el uso de librerías dinámicas hechas en C++. 1. Introducción En esta memoria no se detallará el uso del lenguaje C++ (ni tampoco de VB). Para eso en la web existen excelentes manuales. Tan sólo se explicará cómo sacarles el mejor provecho a ambos. El lector probablemente se pregunte por qué el utilizar C++ aumentará el rendimiento de los programas hechos en Visual Basic. La respuesta es simple: Mientras que VB es un lenguaje interpretado, C++ es un lenguaje compilado. Esto significa que el ordenador, cuando ejecuta un programa hecho en VB debe traducir al código del ordenador la instrucción actual la cual, luego de ser finalizada, el ordenado pasa a traducir la siguiente y se olvida de lo que hizo en el paso anterior. Si tenemos una estructura que se repite constantemente (ya sea una función, o un bucle) esto constituirá una gran pérdida de rendimiento, ya que cada vez que se ejecute deberá traducir el código. VB cuenta con un compilador. Sin embargo este proceso no logra escribir directamente el código de la máquina, sino que es un intermedio entre el código fuente y el código de máquina que, si bien aumenta grandemente el rendimiento, no deja de ser un lenguaje interpretado. Un programa compilado con VB siempre dependerá de librerías y nunca podrá ser un stand-alone-proyect (programa que se pueda ejecutar en cualquier PC) El lenguaje C/C++, por el contrario es un lenguaje compilado. Esto significa que para que pueda ser ejecutado, antes deberá haber sido compilado. Vale decir que todo el código fue traducido al lenguaje del ordenador, consiguiendo importantes optimizaciones en velocidad, en espacio e incluso pudiendo aprovechar las ventajas de cada arquitectura de PC en particular. Otro de los factores que hacen que los programas hechos con C/C++ sea más veloces que los hechos en VB es que C/C++ es un lenguaje de mucho más bajo nivel que VB. Si el lector se pregunta qué significa ser de bajo o alto nivel le propongo este simple ejercicio. Es importante que haga lo que le pida inmediatamente sin pensarlo. Tome una hoja y dibuje una línea horizontal en la mitad de la hoja. Esa línearepresenta el ordenador. Ahora Ud. el usuario se representará como un punto. Rápido y sin pensar dibuje el punto donde crea conveniente (sobre o bajo la línea). Lo dibujó por arriba de la línea ¿Verdad? Esto significa que Ud. domina al ordenador. (Si lo dibujó bajo la línea significa que Windows está dominando al ordenador y a Ud. ;-) ). Los lenguajes pueden estar más cerca de la línea horizontal (ordenador) o más cerca del usuario. Los lenguajes que están cerca del lenguaje del ordenador se los conoce como de bajo nivel. Son extremadamente potentes, pero difíciles de manejar (Assembler o un poco más arriba C/C++). Los lenguajes que están cerca del lenguaje del usuario (habla inglesa) se los conoce como de alto nivel. Es muy fácil hacer cosas con ellos, pero están limitados (SQL o un poco más abajo VB). NOTA: Este tutorial fue hecho en mis ratos libres en mi casa, donde tengo Debian GNU/Linux como sistema operativo. Esto puede significar que los resultados que se muestran en este tutorial pueden ser diferentes a los obtenidos por el lector. 2 Breve resumen de C++ (Diferencias con VB) Cómo se dijo en la introducción, este no es un tutorial de C++. En este apartado me limitaré a refrescarle la memoria a nuestro lector de las cosas que ya sabía de C++. Si nuestro lector recuerda bien el manejo de C++, entonces le recomiendo que se saltee este apartado. Si, por el contrario, nuestro lector no conoce C++, entonces le recomiendo que antes de continuar lea algún tutorial de los que podrá encontrar en la web. 2.1 Conceptos generales de C++ Lo primero que se deberá recordar es que C/C++ son lenguajes case-sensitive, esto significa que, a diferencia de VB, las mayúsculas son diferentes a las minúsculas. Por ejemplo las variables Pepe, pepe, PEPE, pEpe o cualquier otra combinación, son variables diferentes. Todas las funciones en C/C++ están escritas en minúsculas. Esto significa que si queremos declarar una variable de este tipo, el compilador nos dará un error: Char Caracter; Esto es porque Char no es lo mismo que char. Otra característica de C/C++ es que son de formato libre: El compilador generalmente ignora los espacios, tabuladores y enters. ¿Entonces cómo sabe el compilador dónde termina una instrucción? (VB utiliza el enter). Para definir el fin de línea se utiliza el carácter punto y coma ( ; ). Los comentarios en C tradicionalmente estaban encerrados entre /* y */. Este sistema de comentarios continuó siendo soportado por C++. Sin embargo C++ adoptó un nuevo sistema (luego adoptado también por C en versiones recientes) que consiste en tomar como comentario todo lo que esté a la derecha del símbolo //. Este tipo de comentario (conceptualmente idéntico a la comilla simple (') en VB) es preferible, ya que los comentarios /* */ no se pueden anidar. Ej. /* Esto será un comentario de múltiples líneas*/ // Esto es un comentario de una sola línea /* Esto dará /* un */ error */ Siendo que los comentarios /* */ en C/C++ no pueden ser anidados, en el último ejemplo anterior solo se tomará como comentario lo que está pintado en verde: /* Esto dará /* un */ <- Aquí finaliza el comentario error */ <- Esta línea dará error Vale decir que el comentario se cierra con el primer */ que encuentre. Una gran diferencia que tiene C/C++ con VB es la declaración de variables. Mientras que si en VB ponemos: Dim A as Integer, B, C Definirá las variables A como Integer, pero a B y C como Variant. Todas las variables estarán iniciadas con valor 0 (o “” si es String o Variant) Mientras que en C/C++ si se pone: int A, B, C; Las variables A, B, C serán todas tipo int y ninguna de ellas está inicializada. Esto significa que tendrán el valor que tenía la memoria en el momento de crearlas. Este valor se lo conoce como garbage o basura. Para inicializar una variable en C++ podemos hacer: int A = 0, B = 0, C= 1; //Declaro e inicializo las variables. int D, E, F; //Sólamente declaro variables D = E = F = 0; //Asignación múltiple de valores. La asignación es de derecha a izquierda. La asignación múltiple no existe en VB. Por el contrario, cuando VB se encuentra con ellas trata de evaluarla lógicamente. Ej: D = E = 5 Esa línea en C/C++ hará que tanto D como E valgan 5, mientras que VB sólo asignará valores a D y este será True, si E vale 5 o False si E es distinto de 5. NOTA: Aunque en el lenguaje C tradicional es necesario declarar las variables al inicio del procedimiento, en C++ se las puede declara en cualquier lado. (Esta práctica es aceptada también por compiladores de C recientes.) Finalmente recordamos que los programas en C/C++ comienzan la ejecución en la rutina main. Generalmente veremos la rutina main definida de esta manera: int main(int argc, char *argv[]) o la análoga: int main(int argc, char **argv) aunque también podremos encontrarla de otras formas. Una última diferencia notaremos entre C/C++ y VB. Mientras que en VB definimos y declaramos las funciones en el mismo lugar; en C/C++ pueden hacerse en diferentes lugares, pero todas las funciones deberán estar declaradas antes de comenzar la ejecución del programa (int main (void)) NOTA: En VB existen las funciones y los procedimiento. La diferencia entre ellos es que el procedimiento no retorna ningún valor. En C/C++ no existen los procedimiento, sino que son todas funciones. Si se quiere que la función no retorne ningún valor, entonces se declarará la función que retorne un valor void (vacío) Ej. #include <iostream> using namespace std; void salude(void) //Defino y declaro la función en el mismo lugar { cout << "¡Hola mundo!" << endl; } int main(int argc, char *argv[]) { salude(); return EXIT_SUCCESS; } En el ejemplo anterior, siendo que la función salude está antes que main, la función se declara y define en el mismo lugar. Si, por el contrario, ponemos la función salude luego que main, el compilador nos dará un error diciendo que la función salude está usada antes de ser declarada. Esto se soluciona muy fácilmente definiendo la función antes que la función main. #include <iostream> using namespace std; void salude(void); //Aquí solo declaro la función salude. int main(int argc, char *argv[]) { salude(); return 0; } void salude(void) //Aquí defino la función que ya había declarado { cout << "Hello, world!" << endl; } NOTA: Si este programa finaliza su ejecución antes de que el lector haya podido observar el resultado, pruebe poner antes de la línea return, la siguiente instrucción: system(“pause”); Declarar una función es simplemente decirle al compilador que va a existir en algún lado una función que va a tomar los parámetros definidos y retornará el tipo de variable especificado. Definir una función es escribir el procedimiento que hará esa función. NOTA: VB utiliza el mismo concepto cuando se utilizan librerías dinámicas. Ej. Public Declare Sub salude Lib “c:Libreria.dll” () Estamos indicando a VB (declaramos) que utilizaremos una función definida en otra parte. 2.2 Variables 2.2.1 Tipos de variables El lector recordará que C++ cuenta con los siguientes tipos básicos de datos: char: Generalmente para almacenar un carácter, pero también puede servir para números pequeños) int: Números enteros float: Número de precisión de coma flotante double: Número de precisión de coma flotante capaz de almacenar números mayores que con float. El lector deberá recordar que el tamaño de las variables no es fija; sino que depende del compilador y de la arquitectura del ordenador. Para saber cuantos bytes ocupan los tipos de variables en nuestro C++, debemos utilizar la función sizeof(). #include <iostream> using namespace std; int main(int argc, char *argv[]) { cout << "Tamaño de char: " << sizeof(char) << " bytes" << endl; cout << "Tamaño de int: " << sizeof(int) << " bytes" << endl; cout << "Tamaño de float: " << sizeof(float) << " bytes" << endl; cout << "Tamaño de double: " << sizeof(double) << " bytes" << endl; } Este programa, utilizando el compilador g++ para GNU/Linux de x86 da el siguiente resultado: Tamaño de char: 1 bytes Tamaño de int: 4 bytes Tamaño de float: 4 bytes Tamaño de double: 8 bytes 2.2.2 Modificadores En el punto anterior recordamos los tipos de variables básicos. Sin embargo C++ cuenta con modificadores. A saber: signed: Especifica que el tipo de variables debe guardar el signo. unsigned: Especifica que la variable no tendrá signo y por lo tanto podrá el compilador utilizar el byte que ocuparía el signo como un dato, duplicando de ese modo la capacidad de la variable. short: Puede (depende del compilador) hacer que el espacio asignado al tipo de variable sea menor long: Puede (depende del compilador) hacer que el espacio asignado al tipo de variable sea mayor. Signed y unsigned no modifican la cantidad de bytes que ocupa una variable, pero si el tamaño máximo y mínimo que puedan almacenar. En contraste tenemos que short y long si pueden (dependiendo del compilador) modificar el tamaño en bytes ocupado por la variable. NOTA: No todos los modificadores pueden ser aplicados a todos los tipos de variables. 2.2.3 Punteros Una diferencia notable con VB es que C/C++ utiliza punteros. Este concepto realmente útil generalmente lleva algún tiempo para que un usuario de VB lo logre incorporar del todo. La idea es la siguiente: Existen 2 formas de poder acceder a una variable: Por su nombre o por su dirección. El puntero es justamente eso: Acceder a la variable a través de su dirección. La idea del puntero probablemente haya nacido de la imposibilidad de algunos lenguajes de pasar valores de una función por referencia. Siendo que en C solamente se puede pasar parámetros por valor, es de importancia crucial el uso de punteros ya que permite modificar el valor de una variable fuera de esa función. C++ suple esa carencia e introduce el pasaje de valores por referencia, pero aun sigue siendo más claro la utilización de punteros. Un dato de mucha importancia es que en C/C++, al contrario de lo que podría pensarse, el siguiente código: int* pVal1, pVal2, pVal3; No declara 3 punteros int, sino sólo 1: pVal1, los otros 2 son sólo variables int. Esto hace que sea altamente desaconsejable declarara así las variables. Podría hacerse de la siguiente manera: int *pVal1, *pVal2, *pVal3; Esto sí crea 3 variables puntero int. Veamos los siguientes ejemplos. #include <iostream> using namespace std; void SumarUno(int); //Notar que no es necesario especificar el nombre de la variable, sólo el tipo int main(int argc, char *argv[]) { int valor = 5; cout << "La variable, antes de la función, tiene el valor: " << valor << endl; SumarUno(valor); cout << "La variable, luego de la función tiene el valor: " << valor << endl; } void SumarUno(int numero) { cout << "La variable llega a la función con el valor: " << numero << endl; numero++; cout << "La variable sale de la función con el valor: " << numero << endl; } El resultado es este: La variable, antes de la función, tiene el valor: 5 La variable llega a la función con el valor: 5 La variable sale de la función con el valor: 6 La variable, luego de la función tiene el valor: 5 Significa que la modificación solamente tuvo lugar dentro de la función SumeUno. Tradicionalmente (y es la opción que utilizaremos a lo largo de este tutorial), si se quería hacer que se modifique permanentemente el valor de la variable se debía recurrir al uso de punteros. Ej: void SumarUno(int*); //Notar que no es necesario especificar el nombre de la variable, sólo el tipo int main(int argc, char *argv[]) { int valor = 5; cout << "La variable, antes de la función, tiene el valor: " << valor << endl; SumarUno(&valor); //Notar que se pasa la dirección y no el valor cout << "La variable, luego de la función tiene el valor: " << valor << endl; } void SumarUno(int* numero) //Se espera un puntero y no un valor { cout << "La variable llega a la función con el valor: " << *numero << endl; *numero = *numero +1; cout << "La variable sale de la función con el valor: " << *numero << endl; //Notar que en esta función sólo se trabaja con el valor al que apunta el puntero } Otra forma de hacer lo mismo es pasando valores por referencia. Esta opción sólo es válida con C++ void SumarUno(int &numero); //Especificamos que se pasará por referencia int main(int argc, char *argv[]) { int valor = 5; cout << "La variable, antes de la función, tiene el valor: " << valor << endl; SumarUno(valor); //Ahora pasamos valor y no su ubicación cout << "La variable, luego de la función tiene el valor: " << valor << endl; } void SumarUno(int &numero) { cout << "La variable llega a la función con el valor: " << numero << endl; numero++; cout << "La variable sale de la función con el valor: " << numero << endl; } Notar que hacer esto es idéntico a lo que se hace en VB especificando ByRef. Lamentablemente el autor de este tutorial prefiere la opción anterior y de este tipo de pasaje no se hablará más, quedando a juicio del lector el utilizarlo. 2.2.4 Matrices Una matriz es un arreglo de elementos. Es una sucesión de valores. Internamente en C/C++ no existe un concepto de matriz como el que tiene VB. C/C++ en realidad utiliza los punteros para emular un arreglo. Cuando creamos una matriz en C/C++ estamos simplemente reservando espacios en memoria, pero de ningún modo establecemos límites. En VB podemos hacer: Dim Matriz(2 to 10) As Integer Esto nos reservará 9 espacios en la memoria y VB nos impedirá llamar a elementos menores a 2 y mayores que 10 Si en C/C++ hacemos int Matriz[10]; El programa reservará 10 espacios en la memoria (del 0 al 9), pero nada nos impedirá de llamar a un elemento fuera de la matriz, lo que podría provocar errores en el programa difíciles de depurar. Notar que en VB las matrices se especifican por límites, mientras que en C/C++ se hacer por número de elementos. ¿Qué es lo que hace el programa cuando se encuentra con la orden anterior? Podríamos resumirlo como: 1º Se fija cuántos bytes ocupan el tipo de variables especificados (en el caso anterior era int. que en mi compilador son 4 bytes) 2º Reserva un espacio en memoria contiguo de exactamente 4 * 10 bytes (son 10 elementos de 4 bytes cada uno) ¿Qué hace el programa cuando asigna un valor al elemento 5 por ejemplo? Matriz[4] = 12; //Recordar que el 0 es el 1º elemento Lo que hace es averiguar la posición del 1º elemento de la matriz. A esa posición le suma 5 (posiciones) * 4 (bytes). En esa posición almacena el valor 12 (o el que hayamos especificado) Si hacemos Matriz[10] = 1; El programa no nos dará ninguna advertencia ni error y ejecutará la orden tal como lo pedimos, pero estamos escribiendo en un espacio que no fue inicialmente reservado para el arreglo Matriz. Dicho en otras palabras: Es posible que sin querer estemos cambiando el valor de otras variables. Todo esto es simplemente porque Matriz es simplemente un puntero (y no un arreglo). Tanto es así que si queremos averiguar la dirección de memoria de Matriz podemos hacer: cout << "La dirección de Matriz[0] es: " << &Matriz[0] << endl; o cout << "La dirección de Matriz[0] es: " << Matriz << endl; Notar que la segunda forma de averiguar la dirección sólo es posible si Matriz es un puntero. El siguiente ejemplo muestra cómo actúa internamente un arreglo: #include using namespace std; int main(int argc, char *argv[]) { int Matriz[10]; //Reservamos espacio en memoria int *pMatriz = Matriz; //Creamos un puntero apuntando a Matriz //El siguiente bucle será para cargar datos a Matriz for (int i = 0; i <= 9; i++) { *pMatriz = i; //Equivalente a Matriz = i pMatriz++; //Ver nota } //Mostrar los valores for (int i=0; i <= 9 ; i++) cout << "Matriz[" << i << "] = " << Matriz << endl; } NOTA: pMatriz++ hace que el puntero pase a la siguiente posición. Si pMatriz es un puntero de int, significa que, para mi compilador, ocupará 4 bytes. (Ej. Si pMatriz apunta a 0x10000; luego del operador ++, apuntará a 0x10004) 2.2.5 Estructuras y Clases En VB tenemos la posibilidad de utilizar tipos definidos por el usuario mediante Type/ End Type. También podemos utilizar Clases a partir de agregar a nuestro proyecto un módulo de clase. Estas tipos se pueden materializar en C mediante estructuras struct. En C++, además de struct, existe class. No existe otra diferencia entre struct y class que, mientras que en struct es predeterminado que las definiciones sean públicas, en class son privadas. En este tutorial sólo se utilizarán las clases. Como ejemplo pondré una clase no muy útil, pero si explicativa que sirve para obtener la media geométrica (hipotenusa) entre dos valores: #include #include using namespace std; class clsCoordenadas { private: //Es predeterminado pero igual lo pongo float X; float Y; public: clsCoordenadas(void) ; //constructor clsCoordenadas(float valX, float valY); //constructor sobrecargado ~clsCoordenadas(void); //destructor float Hipotenusa(void) ; float Hipotenusa(float valX, float valY); //Funcion sobrecargada void AsignarX (float X); void AsignarY(float Y); void AsignarXY (float X, float Y); }; int main(int argc, char *argv[]) { clsCoordenadas c1, c2, c3(1,2); c1.AsignarXY(3,4); c2.AsignarX (5); c2.AsignarY(6); cout << "Hipotenusa de c1: " << c1.Hipotenusa() << endl; cout << "Hipotenusa de c2: " << c2.Hipotenusa() << endl; cout << "Hipotenusa de c3: " << c3.Hipotenusa() << endl; cout << "nNueva Hipotenusa de c1: " << c1.Hipotenusa(7,8) << endl; } clsCoordenadas::clsCoordenadas(void) //Constructor { } clsCoordenadas::clsCoordenadas(float valX, float valY) //Constructor sobrecargado { AsignarXY(valX, valY); //Llamada a una función interna } clsCoordenadas::~clsCoordenadas(void) //Destructor { } float clsCoordenadas::Hipotenusa(void) { float f; f = sqrt( pow(X,2) + pow(Y,2) ); return f; } float clsCoordenadas::Hipotenusa(float valX, float valY) { AsignarXY(valX, valY); return Hipotenusa(); } void clsCoordenadas::AsignarX (float valX) { X = valX; } void clsCoordenadas::AsignarY(float valY) { Y = valY; } void clsCoordenadas::AsignarXY(float valX, float valY) { X = valX; Y = valY; } Algunas cosa dignas de notar: 1º Todas los clases debe tener, al menos un constructor y un destructor. En el ejemplo mostrado hemos puesto 2 constructores. Los constructores y destructores son una funciones muy características que no retornan ningún valor (ni siquiera un valor void como se puede observar) El constructor sirve para asignar valores y hacer los procedimientos necesarios al iniciar la clase. El destructor, por el contrario, se encarga de hacer los procedimientos necesarios al terminar la clase. Uno de los procedimientos más importantes consiste en quitar de memoria ciertos tipos de variables que, de otro modo, quedarían ocupando espacio hasta que se reinicie el ordenador. En el ejemplo vemos cómo en la siguiente instrucción: clsCoordenadas c1, c2, c3(1,2); el programa, dependiendo de los parámetros utiliza el constructor correspondiente. 2º En C++ podemos tener funciones con el mismo nombre. Siempre que, al menos uno del tipo de variables de los parámetros sea diferente, C++ los tomará como funciones diferentes. A esto se lo conoce como funciones sobrecargadas (u overloaded). En nuestra clase tenemos que el constructor y la función Hipotenusa están sobrecargadas. 3º Vemos como si bien hemos definido las funciones de la clase bajo la función main, la declaración de las mismas se hizo antes. Esto pide a gritos que sea puesto en un archivo header (extensión .h) y que se lo incluya, pero eso no es tema de este tutorial. El lector ya debería saber hacer eso. 2.2.6 Variables públicas Si en VB poníamos un módulo y en el escribíamos: Public A as Integer Automáticamente esa variable A pasaría a estar accesible desde cualquier parte del programa. Este comportamiento no existe en C/C++. Todas las variables declaradas antes que la definición de cualquier función en C/C++ significa que dicha variable será accesible desde cualquier parte de ese archivo. Esto sería comparable a cambiar el código anterior de VB por Dim A as Integer Donde la variable A sólo está disponible dentro del módulo. ¿Cómo hacer entonces para que en C/C++ podamos tener variables accesibles desde cualquier parte del proyecto y no sólo del archivo actual? (Utilizar con cuidado ya que no es una buena práctica utilizar variables globales) Se debe declarar en todos los archivos donde se hará referencia a la variable como pública, pero todas las definiciones menos una deberá tener la palabra extern. Ej. [Archivo: main.cpp] int VariableGlobal; [Archivo: modulo.cpp] extern int VariableGlobal; [Archivo: otro.cpp] extern int VariableGlobal; Esto indica al compilador que en el archivo modulo.cpp haga de cuenta que crea una variable, pero que en realidad estará utilizando otra variable que debió haber sido definida en alguna otra parte del proyecto. 3 Primera interacción entre VB y C++ Si bien C/C++ no necesita nada más que un editor y un compilador, suele ser muy útil utilizar una IDE, ya que ayudan mucho al desarrollo de nuestras aplicaciones. La IDE que se utilizará en este proyecto es (por razones de tradición) Dev C++ de Bloodshed, que es libre y puede ser descargada de (www.bloodshed.net). Lamentablemente el proyecto Dev C++ está muerto. Desde febrero del 2005 que no hay una nueva versión. Probablemente el próximo tutorial que haga se base en la IDE, también libre, Code::Blocks (www.codeblocks.org). Code::Blocks es un proyecto muy activo (todos los días hay nuevas versiones), pero todavía el Dev C++ sigue siendo más robusto. 3.1 Nuestro primer programa Ahora que tenemos los conceptos generales de ambos lenguajes procuraremos crear un ejemplo de un proyecto que utilice ambos lenguajes. Nuestro primer programa consistirá, simplemente en sumar una unidad a un número o valor dado. Esta función la haremos tanto con pasaje de variables por valor como por referencia (punteros) 3.1.1 La librería Dll Iniciemos Dev C++. Luego ejecutemos Archivo -> Nuevo -> Proyecto. Dev C++ nos mostrará una nueva ventana donde se verán varios “templates”. Elijamos el que dice Dll, pongámosle un nombre coherente al proyecto y especifiquemos (si es que no lo está) que el proyecto será en C++. Luego demos Aceptar. Luego de especificarle dónde guardará el archivo de proyecto (es aconsejable un proyecto por directorio) tendremos cargado en memoria 2 archivos: dllmain.cpp y dll.h Ahora definiremos las funciones que utilizaremos desde VB. (Copiar las siguiente funciones al final del archivo dllmain.dll) void SumeUnoPorReferencia (long *A) { *A = *A + 1; } long SumeUnoPorValor (long A) { return ++A; } El lector no debiera tener problemas en saber exactamente lo que hace el código anterior por lo que no lo explicaré. Notemos que cuando pasamos el valor por referencia, entonces no necesitamos retornar ningún valor (ya que el valor mismo está en la variable), por ello hemos definido un procedimiento (función que no retorna valores). Por el contrario, en el pasaje por valor debemos devolver un valor, ya que el cambio que hicimos en la variable se pierde al finalizar la función. Este comportamiento no es siempre así, pero simplemente quise aprovechar la oportunidad para definir una función y un procedimiento para explicar las diferencias cuando llegue a la parte de VB. Bien, ya hemos definido las funciones, ahora queda declararlas. El problema es que estas funciones podrán ser utilizadas desde afuera de la librería (y de hecho ese es el fin de las mismas), por lo que la convención para declararlas difiere de lo que el lector estaba acostumbrado. (Por supuesto que las funciones internas que sólo se utilizarán dentro de la librería siguen la convención que conocía el lector) El siguiente es la declaración de las funciones (para que sean públicas) extern "C" DLLIMPORT void __stdcall SumeUnoPorReferencia (long *A); extern "C" DLLIMPORT long __stdcall SumeUnoPorValor (long A); NOTA: En la declaración hemos utilizado DLLIMPORT que el template de Dev C++ ya tenía definido. En realidad poco importa que en la declaración se especifique el nombre de la variable (lo mismo que en las declaraciones tradicionales). Lo único que interesa es el tipo de variable. Notemos que la diferencia entre las declaraciones tradicionales y este nuevo tipo es que delante de la declaración debemos poner extern "C" DLLIMPORT, y entre el tipo devuelto y el nombre de la función __stdcall. El extern “C” se debe a que las funciones son exportadas como funciones de C. Esto significa que si bien C++ diferencia funciones que difieran en la cantidad de parámetros (funciones sobrecargadas u overloaded), C no lo hace y, por tanto, no podremos hacerlo (por suerte, ya que sería un verdadero problema el utilizar funciones sobrecargadas en VB) El __stdcall se debe a que para utilizar en VB una función, esta no debe ser __cstd como es predeterminado, sino __stdcall Ahora sólo resta compilar la librería. Para esto debemos ejecutar el menú Ejecutar -> Compilar (o presionar su acceso rápido: Ctrl + F9) De modo predeterminado, Dev C++ crea la librería, archivos relacionados y el código objeto en el mismo directorio donde se encuentre el proyecto (archivo .dev). Para cambiar esto se debe ejecutar Proyecto -> Opciones de Proyecto (o Alt + P) y en la solapa opciones se deben especificar las rutas deseadas. Esto es importante porque en VB deberemos especificar la ubicación exacta de la librería. 3.1.2 La interacción con VB En VB no se puede definir una función en un lugar y declararla en otro, ya que la declaración y definición van en el mismo lugar. Ej. Private Sub Funcion1() 'Declaro y defino en el mismo lugar. End Sub Pero… qué pasa cuando la función si se definió en otro lado (en un archivo ajeno a VB como la librería). En ese caso VB procede de la misma forma que C/C++ y se debe declarar la función antes de utilizarla. Para hacer esto, VB cuenta con la instrucción Declare. Al igual que cualquier función, las declaradas con Declare pueden ser públicas (public) o privadas (private). Si las declaramos en un formulario (ventana), entonces no puede ser otra cosa que privado. (sólo pueden ser llamadas desde el mismo formulario. Si las declaramos en un módulo, pueden ser publicas (globales: pueden ser llamadas desde cualquier parte del proyecto) o privadas (sólo se las puede llamar dentro del mismo módulo). Es digno de recordar que las funciones que en C++ no retornaban valores (void), en VB serán Sub; mientras que las que sí lo hacían, en VB serán Function. La sintaxis de Declare, dependiendo si retorna o no valores es la siguiente (Tomado de la ayuda de e VB sobre el comando Declare, por lo que es altamente aconsejable su lectura) Sintaxis 1 [Public | Private] Declare Sub nombre Lib "nombre_biblioteca" [Alias "nombre_alias"] [([lista_argumentos])] Sintaxis 2 [Public | Private] Declare Function nombre Lib "nombre_biblioteca" [Alias "nombre_alias"] [([lista_argumentos])] [As tipo] El lector debiera estar familiarizado con todas las palabras claves que figuran en el código anterior, tal vez con excepción de Lib y de Alias En Lib, especificamos la ruta completa a la librería (puede ser una ruta relativa) Definir Alias, no es tan simple, ya que existe un estrecho paralelismo con nombre. Si se omite Alias (que es opcional), entonces VB toma que Alias es nombre. Una definición rápida sería: nombre es cómo se llamará la función desde VB. Alias es cómo se llama la función en C++. Si se omite Alias, en nombre, debería poner el nombre exacto de la función (o procedimiento de la librería). Recordar que, aunque VB no lo es, C++ es case sensitive. Por lo tanto se debe tener cuidado con el uso de mayúsculas. Ahora surge un problema. ¿Qué pasa si el nombre de la función en C++ es una palabra clave en VB o cuando en C++ hemos definido dos funciones diferentes por ser case-sensitive, pero en VB no lo son? Para eso viene en nuestra ayuda el parámetro Alias. Supongamos que en C++ hayamos definido dos funciones para ser utilizadas desde VB: Dim y dim. En ese caso tenemos 2 problemas. El primero es que las dos funciones para VB son las mismas (VB no es case-sensitive); El segundo es que ambas se llaman como una palabra clave en VB. Cómo solucionar eso entonces. Declare Sub cDim Lib “../Librerias/Prueba.dll” Alias “Dim” () Declare Sub cdim1 Lib “../Librerias/Prueba.dll” Alias “dim” () NOTA: Fijarse que hemos definido rutas relativas. IMPORTANTE: Hay que tener cuidado con la definición de rutas relativas, ya que estas no están referidas a donde está el proyecto, sino desde donde se está ejecutando. Vale decir que si bien en el compilado ambas direcciones coinciden, si se corre el programa desde VB, todo va a estar referido a la ubicación de Visual Basic. Con la ayuda de Alias y nombre hemos podido salir del paso. Por supuesto, no es una práctica remendada definir funciones en C++ que vayamos a tener problemas en VB, pero logramos utilizar ambas funciones en VB (eso si, se deberán llamar a las como cDim o cdim1 en vez de Dim o dim). El nuevo desafío ahora consiste en poder reproducir los parámetros de las funciones en C++ en VB. El primer problema es el del tamaño de bytes. Como se mencionó anteriormente (punto 2.2.1), la cantidad de bytes de C++ no es fija. Por lo tanto es recomendable que el lector haga una tabla con las equivalencias de bytes entre las variables (enteras y con punto flotante) entre C++ y VB. El modo de hacerlo está en el punto 2.2.1. Para obtener cuánto ocupan en VB utilice Len o directamente lea la ayuda. El segundo problema es establecer si el pasaje de variables era por valor o por referencia. Aunque el pasaje por referencia es predeterminado y, por lo tanto podría omitirse el ByRef, yo no lo aconsejo y siempre escribo ByVal o ByRef según corresponda. Regla de oro: Si en C++ utilizamos un valor, entonces debemos anteponer ByVal. Si utilizamos un puntero, entonces podemos (altamente aconsejable) anteponer ByRef. El no cumplir esa regla ocasionará problemas difíciles de depurar. NOTA: Las declaraciones, al igual que en C++, se deben hacer antes de cualquier función. Esto significa que debe ir en el encabezado (ya sea del formulario o del módulo) Ejercicio 1: Declarar y utilizar con VB las funciones que hemos hecho en C++ (Respuestas al final tutorial) 4. Pasajes más complejos entre VB y C++ Con lo que hemos visto hasta ahora el lector no tendrá ninguna dificultad en hacer funciones en C++ que utilicen simples números (o punteros) para utilizarlas en VB, pero ¿Qué pasará cuando el lector se entusiasme e intente pasar matrices, tipos definidos por el usuario (UDT), o una cadena de texto? Se requiere que el lector haya asimilado bien el punto 2 de este tutorial, ya que en esa sección se hará constante mención a él. 4.1 Pasaje de matrices Tal como fue explicado en el punto 2, existen grandes diferencias entre una matriz de VB y una de C++. Si el lector recuerda, se hizo expresa mención que en C++ las matrices no son otra cosa que punteros, por lo tanto esa será la solución al problema. Ej, En VB Dim Mat() As Integer ReDim Mat (4) Funcion Mat (0), UBound(Mat) En C++ void Funcion(short* Mat, short Rango) NOTA: Al especificar Mat(0) como primer parámetro en la función de VB estamos haciendo que el puntero de C++ apunte al primer elemento de la matriz. El modo de acceder a los elementos de la matriz Mat fue descriro en el apartado 2.2.4 Existen otros modos de acceder a una matriz hecha en VB desde C++. Una es directamente creando la clase SAFEARRAY que es la que utiliza VB, pero realmente por sencillez y velocidad, la que más conviene es la que he comentado. Ejercicio 2: Crear una matriz dinámica en VB y asignarle valores. Crear una función en C++ devuelva la sumatoria de todos los elementos. (Respuestas al final tutorial) 4.2 Pasaje de UDT La solución en este caso viene de la mano de las intrucciones Type/End Type en VB y class o struct en C++ Sabiendo que lo que se envía desde VB debe ser interpretado de exactamente la misma forma en C++ podemos decir que no existe ninguna traba en utilizar UDT en funciones de C++ con datos de VB siempre y cuando en ambos lados exista la misma definición del tipo. Aunque el lector, llegado a este punto, se podría bien imaginar la solución del problema, me temo que hay algunos puntos que deberé explicar: En primer lugar, el pasaje de valores será siempre por referencia en VB y punteros en C++ En segundo lugar, el lector deberá recordar la diferencia que existe entre trabajar un una clase (o estructura) y un puntero a una clase (o estructura) Si en C++ defino esta clase: class clsPrueba { int A; int B; }; Cuando trabajo con valores se debe operar de la siguiente manera: clsPrueba Variable; Variable.A = 1; Variable.B = 2; Sin embargo, cuando se trabaja con punteros la cosa cambia. clsPrueba *pVariable = Variable; Variable->A = 3; Variable->B = 4; Notar que cuando se trabaja con valores, se separan las variables por el signo “.”. Cuando es un puntero, no se especifica el signo “*” al principio para designar valor y no dirección y además se cambia el signo “.” por “->” C/C++ hace optimizaciones en la velocidad que, a veces, entorpecen la comunicación con VB. ANSI C no especifica cuanto debe ocupar un determinado tipo de variable, sino entre qué rangos se debe encontrar. Esto es porque implícitamente está permitiendo al compilador utilizar variables que ocupen más bytes de lo que realmente necesitan para crear un ejecutable más veloz. VB desconoce de estas optimizaciones y será imposible trabajar conjuntamente si no se toman medidas en C++. El problema viene dado cuando en VB definimos un UDT con diversos tipos de variables. En VB: Type typPrueba A As Double '8 bytes B As Double '8 bytes C As Integer '2 bytes End Type La variable typPrueba debiera ocupar 18 bytes (8 + 8 + 2) y realmente eso es lo que ocupa. Sin embargo la misma definición en C++ puede traernos alguna sorpresa. En C++ class clsPrueba { double A; //8 bytes double B; //8 bytes short C; //2 bytes }; Aunque se esperaría que la clase clsPrueba ocupe 18 bytes, puede ocupar más. C++ puede conseguir importantes mejoras en la velocidad de ejecución haciendo que la variable short C ocupe 4 bytes o incluso 8 (dependiendo del compilador) y, por ende, clsPrueba ocupará 20 o 22 bytes. Sin embargo podemos especificarle a C/C++ que no realice esa optimización, ya que no nos importa el rendimiento y en vez nos interesa que ocupe la menor cantidad de memoria posible... o simplemente porque vamos a intereactuar con VB donde esas optimizaciones generarán errores. Para ello debemos utilizar el atributo packed. Con este atributo las clases ocuparán exactamente lo mismo que en VB. class __attribute__ ((__packed__)) clsPrueba { double A; //8 bytes double B; //8 bytes short C; //2 bytes }; Ahora la clase clsPrueba ocupará realmente los 18 bytes esperados. NOTA: delate y detrás de las palabras attibute y packed hay doble guion bajo (“_”) Ejercicio 3: Crear un UDT donde se carguen 2 valores (Val1 y Val2. No utilizar matrices) en VB. En C++ deberá hacer una función que retorne la media de ambos valores ((Valor1 + Valor2)/2) (Respuestas al final tutorial) Si el lector quiere poner matrices dentro de su variable UDT, entonces no le quedará más remedio que investigar e implementar en C++ el tipo SAFEARRAY con que cuenta VB. 4.3 Pasaje de variables String Si bien C++ cuenta con un nuevo tipo de variables (no existe en C) llamado string, este no es otra cosa que una clase y no es la misma que la que cuenta VB como tipo básico de variables. El paralelo a String de VB en C++ es LPCSTR Ej. En VB Private Declare Sub Mensaje Lib "Temp.dll" (ByVal Texto As String) Private Sub Command1_Click() Mensaje "Hola" End Sub En C++ void Mensaje (LPCSTR Texto) { MessageBox(0, Texto, "DLL Message", MB_OK | MB_ICONINFORMATION); } NOTA: La definición de la clase LPCSTR está dentro de la librería “windows.h”, por lo tanto, cuando se escriba en la cabecera de nuestro proyecto (dll.h) la declaración de la variable habrá que agregar (si es que no está) una inclusión al mencionado fichero. 5 Depuración de las librerías Dll Si bien este no es tema estrictamente del presente tutorial, será una guía de las metodologías que podrá utilizar para cuando necesite depurar una librería. El lector probablemente cuando haya trabajado con C++ haya tenido la necesidad de utilizar un depurador y si trabajó desde alguna IDE muy probablemente haya hecho una depuración paso a paso. El hecho que en las librerías no exista un punto de comienzo (función main) hace que sea imposible el modo de depuración descrito (a menos que cree una aplicación en C++ que la utilice, pero no creo que valga la pena) Viéndonos desprovistos de tan útil herramienta, debemos buscar soluciones alternativas. 5.1 Depurando con mensajes Depurar un programa no es otra cosa que ir indagando cuánto valen determinadas variables en determinado momento. Una buena forma de hacerlo es a través de las cajas de mensajes (MessageBox) La función que nos brinda esa posibilidad se llama MessageBox y para poder utilizarla debemos incluir la librería “windows.h” (por lo obviamente no es una función del ANSI C) La función MessageBox tiene la siguiente sintaxis. int MessageBox( HWND hWnd, //Ventana (Si es NULL, entonces la ventana de MessageBox no tiene dueño) LPCTSTR lpText, // Texto a mostrar LPCTSTR lpCaption, // Título de la ventana UINT uType // Estilo. ); Utilizaremos esta función con la ayuda de la función sptrinf (definida con la librería C++ estándar cstdio (en C llamada stdio.h)) Para mostrar un ejemplo del uso de la misma, depuraré el ejemplo número 2. short SumarElementos (short *Mat, short Rango) { short sumatoria=0; char cad[100]; //Defino una cadena con cantidad suficiente de espacio sprintf(cad, "InicionRango = %i", Rango); //Escribo los datos necesarios MessageBox(0, cad, "Depurando", MB_OK | MB_ICONINFORMATION); for (short i = 0; i <= Rango; i++) { sumatoria += *Mat; sprintf(cad, "Iteración: %inMatriz: %inSumatoria: %i", i, *Mat, sumatoria); MessageBox(0, cad, "Depurando", MB_OK | MB_ICONINFORMATION); Mat++; } return sumatoria; } 5.2 Utilizando archivos de texto El concepto aquí es el mismo que en el punto anterior, pero utilizar archivos de texto suele ser conveniente para no llenarnos de mensajes (lo que dificultaría aun más el depurar el código). En este caso utilizaremos el tipo de datos FILE*, la función fopen y fclose y la función fprintf. (librería C++ estándar cstdio (en C llamada stdio.h)) Ejercicio 4: Depurar cualquier ejercicio anterior utilizando esta forma. ANEXO: Respuesta a los ejercicios IMPORTANTE: En las respuestas que incluyan código en C++, no se pondrá la declaración de las funciones, ya que el lector perfectamente podrá reconstruir la misma a partir de la definición de las funciones que se escriban. Ante cualquier duda, releer el punto 3.1.1 “La librería Dll” Respuesta ejercicio 1: Private Declare Sub SumeUnoPorReferencia Lib "Ejercicio.dll" (ByRef A As Long) Private Declare Function SumeunoPorValor Lib "Ejercicio.dll" (ByVal A As Long) As Long Private Sub Command1_Click() Dim B As Long B = 5 SumeUnoPorReferencia B MsgBox B End Sub Private Sub Command2_Click() Dim B As Long B = SumeunoPorValor(5) MsgBox B End Sub Respuesta ejercicio 2: En VB Private Declare Function SumarElementos Lib "..LibUltimo.dll" (ByRef Mat As Integer, ByVal Rango As Integer) As Integer Private Sub Command1_Click() Dim Mat() As Integer, i% ReDim Mat(4) For i = 0 To UBound(Mat) Mat(i) = i Next MsgBox SumarElementos(Mat(0), UBound(Mat)) End Sub En C++ short SumarElementos (short *Mat, short Rango) { short sumatoria=0; for (short i = 0; i <= Rango; i++, Mat++) sumatoria += *Mat; return sumatoria; } Respuesta ejercicio 3: En VB Private Declare Function ObtenerMedia Lib "C:VisualBasicPROYECTOSLibUltimo.dll" (ByRef Valores As typEjemplo) As Single Private Type typEjemplo Val1 As Integer Val2 As Integer End Type Private Sub Command1_Click() Dim Valores As typEjemplo Valores.Val1 = 2 Valores.Val2 = 9 MsgBox ObtenerMedia(Valores) End Sub En C++ class clsEjercicio //poner en el archivo de cabecera (dll.h) { short Val1; short Val2; }; float ObtenerMedia (clsEjercicio *Valores) { return (Valores->Val1 + Valores->Val2)/2.; }

Contenido Introducción ¿VB .NET vs. C#? ¿Qué dice Microsoft? Diferencias ¿Y el soporte? ¿Cómo decido? Conclusión Introducción Este artículo ofrece un breve análisis acerca de Visual Basic .NET y C#, los dos lenguajes más utilizados de la plataforma .NET, desde un punto de vista no técnico, sino de lo que ambos lenguajes pueden ofrecer a los desarrolladores; su objetivo es brindar una referencia para los desarrolladores que recién se inician con la plataforma .NET, y aún no deciden qué lenguaje utilizar. Principio de la página ¿VB .NET vs. C#? Pareciera que estos dos lenguajes de la plataforma .NET se basan en una misma especificación; que se traducen a un lenguaje común antes de ser convertidos en código máquina y utilizan los mismos recursos del ambiente de ejecución; las mismas librerías de clases y, sobre todo, que su performace es igual, que no ha sido todavía asimilada, sobre todo por aquellos desarrolladores que anteriormente ya utilizaban lenguajes basados en C. Gran polémica es la que despierta este tema, cada vez que alguien hace la pregunta ¿Cuál lenguaje es mejor: Visual Basic .NET ó C#? Siendo que esta pregunta tan simple puede responderse con otra pregunta igual de sencilla, y que por lo general nosotros mismos nos podemos contestar: ¿Cuál te gusta más? O puesto de otra manera: ¿Con cuál de los dos te sientes más cómodo? Y no es que uno sea mejor que el otro, sino que uno puede acoplarse mejor a nuestras habilidades y necesidades. Ahora, y como anteriormente ha sucedido, no faltará quien suponga que C# es mejor por ser un lenguaje basado en C; sin embargo, ¿Con qué fundamento se hacen estas suposiciones? Si has estudiado un poco la plataforma .NET sabrás ya que todos los lenguajes se “compilan” a un mismo lenguaje intermedio (aún cuando los archivos resultantes de esta compilación sean .EXE ó .DLLl), al cual normalmente se hace referencia como MSIL ó IL; y que además la plataforma cuenta con un componente conocido como CLR (Common Language Runtime) el cual se encarga, entre otras cosas, de convertir estas instrucciones en IL hacia código de máquina justo antes de su ejecución haciendo uso de un compilador JIT. Ahora, el punto importante en este párrafo es que “todos los lenguajes se compilan a un mismo lenguaje intermedio”, pues en ningún momento da pie a suponer que una aplicación escrita en C# nos dará como resultado un mejor IL que la misma aplicación escrita en Visual Basic .NET, o viceversa; tomando el clásico programa de ejemplo “hola mundo”, se puede comparar el IL generado en Visual Basic .NET con el generado en C#. VB .NET Module Hola Sub Main() Console.WriteLine("Hola mundo desde una app en VB!!!" Console.Read() End Sub End Module 1. .method public static void Main() cil managed 2. { 3. .entrypoint 4. .custom instance void System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 5. // Code size 20 (0x14) 6. .maxstack 8 7. IL_0000: nop 8. IL_0001: ldstr "Hola mundo desde una app en VB!!!" 9. IL_0006: call void System.Console::WriteLine(string) 10. IL_000b: nop 11. IL_000c: call int32 System.Console::Read() 12. IL_0011: pop 13. IL_0012: nop 14. IL_0013: ret 15. } // end of method Hola::Main _______________________________________________________________________________________________________ C# class Class1 { static void Main(string[] args) { Console.WriteLine ("Hola mundo desde una app en C#!!!"; Console.Read(); } } 1. .method private hidebysig static void Main(string[] args) cil managed 2. { 3. .entrypoint 4. .custom instance void System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 5. // Code size 17 (0x11) 6. .maxstack 1 7. IL_0000: ldstr "Hola mundo desde una app en C#!!!" 8. IL_0005: call void System.Console::WriteLine(string) 9. IL_000a: call int32 System.Console::Read() 10. IL_000f: pop 11. IL_0010: ret 12. } // end of method Class1::Main ______________________________________________________________________________________________ Lo primero que habrás notado es que el programa en Visual Basic .NET genera tres líneas más de código IL (las líneas 7, 10 y 13) que el programa en C#, y te preguntarás por qué. Esto es simplemente debido a que Visual Basic .NET permite agregar puntos de interrupción en líneas de código no ejecutable, como por ejemplo en un End Sub, y esto lo maneja agregando instrucciones nop (No Operation) al IL generado; sin embargo, estas instrucciones, de las cuales cabe mencionar que su consumo de ciclos de procesamiento es prácticamente nulo, solo son agregadas cuando la compilación se hace en modo de depuración, de manera tal que si compilamos la misma aplicación utilizando la opción Release obtenemos el siguiente IL: VB.NET Module Hola Sub Main() Console.WriteLine("Hola mundo desde una app en VB!!!" Console.Read() End Sub End Module 1. .method public static void Main() cil managed 2. { 3. .entrypoint 4. .custom instance void System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 5. // Code size 17 (0x11) 6. .maxstack 8 7. IL_0000: ldstr "Hola mundo desde una app en VB!!!" 8. IL_0005: call void System.Console::WriteLine(string) 9. IL_000a: call int32 System.Console::Read() 10. IL_000f: pop 11. IL_0010: ret 12. } // end of method Hola::Main ________________________________________________________________________________________________________ Como se puede ver, es prácticamente igual al IL generado por la aplicación escrita en C#, y esto se debe precisamente a que todos los lenguajes de la plataforma .NET son traducidos al mismo IL y a que todos los lenguajes, para poder formar parte de la plataforma, deben cumplir con el CLS (Common Language Specification), que son todas las especificaciones necesarias para ser considerado como compatible, y asegurar la compatibilidad entre componentes escritos en los diferentes lenguajes. Nota: el código presentado en el ejemplo anterior fue generado con el Visual Studio 2003, y para la visualización del IL puedes utilizar la utilería ILDASM.exe incluida con el SDK del .NET Framework. Aún cuando todos los lenguajes de la plataforma .NET son traducidos a un mismo IL, las diferentes opciones de compilación pueden generar un IL drásticamente diferente, con sus consecuentes diferencias en desempeño. Lo que es un hecho es que los diferentes compiladores, por defecto, tienen diferentes opciones de compilación; por esta razón, es importante comprender cual es el resultado de compilar un programa con las diferentes opciones que ofrece un determinado compilador. Entendido esto, se puede asegurar que programas equivalentes, compilados con opciones equivalentes y aún cuando hayan sido escritos en diferentes lenguajes, siempre generaran el mismo IL, que una vez compilado por el CLR, se comportara, y tendrá un desempeño igual. ¿Qué dice Microsoft? Solo basta con echar un vistazo al White Paper "Differences Between Microsoft Visual Basic .NET and Microsoft Visual C# .NET" para darnos cuenta de que ambos lenguajes son considerados igualmente poderosos y que realmente no existen argumentos para suponer que alguno de ellos es superior. El siguiente párrafo ha sido extraído precisamente de la introducción de ese documento. "Debido a las diferencias del pasado entre Microsoft Visual Basic , Microsoft Visual C , y Microsoft Visual C++ , muchos desarrolladores tienen la impresión de que Microsoft Visual C# .NET es un lenguaje mucho más poderoso que Microsoft Visual Basic .NET. Algunos desarrolladores asumen que muchas cosas que son posibles en Visual C# .NET son imposibles en Visual Basic .NET; de igual forma en que muchas cosas que son posibles en Microsoft Visual C 6.0 ó Microsoft Visual C++ 6.0 son imposibles en Microsoft Visual Basic 6.0. Asumir esto es incorrecto. Si bien existen diferencias entre Visual Basic .NET y Visual C# .NET , ambos son lenguajes de programación de primera clase basados en el Microsoft .NET Framework , y ambos son igual de poderosos." Diferencias Si revisamos un poco más este documento, encontraremos que muchas de las diferencias entre los lenguajes son puramente de sintaxis, y muchas tan triviales como que un entero se indica en en VB .NET con la palabra clave Integer, y en C# con la palabra clave int; como la forma de declarar variables, el uso de paréntesis, corchetes y llaves; y en general como las diferencias entre un lenguaje cuya sintaxis es heredada del C y otro cuya sintaxis es heredada del BASIC. Por otra parte también existen diferencias un poco más significativas tales como el chequeo de desbordamientos, el paso de parámetros y la vinculación tardía, puntos que son manejados de manera un poco diferente por ambos lenguajes; además VB .NET incluye, por facilidad y compatibilidad, un conjunto de funciones preconstruidas tales como: LEN, MID, CInt, IsDate, etc., y permite el uso de un manejo de errores estructurado; y por compatibilidad permite también el manejo de errores no estructurado. ¿Y el soporte? He escuchado mucho decir que hay más ejemplos en C# que en Visual Basic.NET; que la mayoría del código escrito hasta ahora en .NET está en C#; que existen más y mejores tutoriales en la Web, y esto es algo que no puedo negar ni afirmar, sin embargo pienso que el grueso de los desarrolladores de Visual Basic, aún no han hecho la transición desde el Visual Basic 6 hacia el Visual Basic .NET, a diferencia de los desarrolladores de C y C++, quienes en su necesidad de poder utilizar una herramienta RAD que les permita aminorar los tiempos de desarrollo, han hecho esta transición lo antes posible. ¿Cómo decido? Si ya has decidido utilizar .NET como plataforma de desarrollo, creo que el enfoque principal debe centrarse en aprender los aspectos del funcionamiento del .NET Framework, y la decisión acerca de cuál lenguaje a utilizar dependerá más de tu experiencia previa con otros lenguajes tales como el C, el C++ ó el Visual Basic, ya que la curva de aprendizaje será mucho menor si eres un desarrollador con experiencia en C y decides utilizar C#; de igual manera, si eres un desarrollador con experiencia en Visual Basic, esta curva de aprendizaje será menor si eliges Visual Basic .NET, ya que esto permite centrarse en aprender los aspectos nuevos y específicos del .NET Framework y no centrarse en aprender aspectos específicos del lenguaje tales como su sintaxis, por ejemplo. Esto no quiere decir que debamos cerrarnos a un solo lenguaje, sino que es más fácil aprender esta plataforma haciendo uso de un lenguaje con el que ya estás familiarizado. Conclusión Ya que ambos lenguajes están basados en la misma plataforma (.NET), y hacen uso de los mismos recursos (.NET Framework), podemos obtener los mismos resultados con uno y otro; lo que nos da la libertad de seleccionar el lenguaje que más se acomode a nuestras necesidades y experiencia previa sin sacrificar la potencia o la funcionalidad que el lenguaje nos ofrece, permitiéndonos esto centrarnos más en aprender los aspectos nuevos de la plataforma, que a fin de cuentas son comunes a todos los lenguajes. Esto no quiere decir que debamos quedarnos con un solo lenguaje; al contrario, una vez que hayamos dominado uno, debemos empezar a aprender otro nuevo, ya que las condiciones en las que desarrollamos aplicaciones no siempre será las mismas pero eso sí, siempre hay que estar preparado. Mario Félix Guerrero es Licenciado en Sistemas de Información del Instituto Tecnológico de Sonora, Cd. Obregón Sonora, México. Posee experiencia laboral mayormente en el Departamento de Tecnologías y Servicios de Información de ese instituto, desarrollando principalmente aplicaciones de escritorio y aplicaciones Web con herramientas tales como Visual Basic 6.0, ASP y SQL Server 2000; ha desarrollado aplicaciones para dispositivos móviles y aplicaciones Web con ASP .net. Ha obtenido la 3ra. Estrella del programa Desarrollador Cinco Estrellas de Microsoft MSDN y es Instructor de esa estrella.

Para comenzar nuestra aventura en el lenguaje Java deberemos realizar unos pasos previos, como instalarnos cierto software imprescindible. Lo primero que nos viene en mente es hacernos con un editor, un programa en el que escribir nuestro código Java. El famoso bloc de notas puede valernos como tal, pero sin un compilador no nos servirá de mucho. Ahora bien... ¿de donde sacamos ese compilador? Sun, la empresa creadora de Java, distribuye gratuitamente el llamado SDK (Software Development Kit), en versiones anteriores llamado JDK (Java Development Kit), un conjunto de herramientas y programas que permiten desarrollar, compilar y ejecutar aplicaciones en Java. El compilador en el SDK o JDK se llama javac.exe. Programar tan sólo con el SDK puede resultar algo tedioso, pues utilizaremos un programa para editar, otro para compilar, otra para el debugger... por ello, se suelen utilizar los llamados IDE´s, aplicaciones que permiten hacer todo eso en un mismo entorno, a través de un sólo programa. Exiten muchos IDE´s para Java, algunos que incluyen sus propias clases y librerías, otros orientados al desarrollo de applets, gratuitos, de pago.... Algunos también no llevan compilador, por lo que tendremos que indicar en la configuración del programa el directorio donde se encuentra nuestro SDK o JDK. Como recomendación, de tipo gratuitos: JCreator: http://www.jcreator.com/ JBuilder Foundation: http://www.borland.com/jbuilder/foundation/index.html

Como ya dijimos desde que comenzamos a hablar de Gambas, que difería mucho con respecto a Visual Basic, ahora aclaremos algunas cosas y terminemos de entender este concepto. La principal diferencia con respecto a Visual Basic 6.0 es el soporte para orientación a objetos. En Gambas, no existen los arrays de controles -muy populares en Visual Basic- pero dispone de un elemento similar llamado group, que utilizado conjuntamente con arrays de objetos ofrecen resultados análogos. Gambas añade algunas propiedades nuevas en algunos de sus controles, como la alineación vertical/horizontal en etiquetas, o algunas propiedades gráficas en el elemento Button (Equivalente a CommandButton de Visual Basic). El acceso a bases de datos es sumamente sencillo y potente. Gambas incluye, al igual que Visual Basic, su propio empaquetador para la distribución de aplicaciones, que permite crear incluso paquetes deb. Los componentes suministrados en Gambas 2.0 son realmente potentes, desde una librería para el manejo de documentos pdf, hasta componentes para imágenes, sockets e informes (equivalentes a Crystal reports u otras herramientas gratuitas alternativas). Gambas es una excelente y potente alternativa a la programación visual ofrecida en Visual Basic para entornos Linux. Su talón de aquiles actualmente es su escasa documentación.