Codigo Latino 9

50

description

Revista de programación en varios lenguajes para los hispanohablantes

Transcript of Codigo Latino 9

Page 1: Codigo Latino 9
Page 2: Codigo Latino 9

Después de.... mucho tiempo Código Latino ha vuelto; mientras en SoloCódigo han ocurrido muchos cambios la revista también ha sufrido uno pequeño, el nuevo Editor seré yo Edo o como me conocían antes en SoloCódigo RadicalEd, Blag muy amablemente me permitió ser el encargado de la revista para seguir mostrando cosas interesantes de los Lenguajes de Programación.

Como es mi primera vez como editor de una revista, pido disculpas por el diseño, yo de diseñador no tengo nada, quien me quiera ayudar con el diseño no me enojo :P , tendremos 2 entrevistas y mucho mucho código tomado de genios de la programación y míos :P

Vamos a cambiar de formato, de ahora en adelante la revista será en .pdf, pero de todas maneras tendremos una versión OnLine para leer.

Espero la disfruten!!!

Esta edic ión es  en honor al  pr imer editor  de  la  revista dejare  su avatar como muestra de   agradecimiento y esta 

entrega será  un regalo especial  para é l .

Page 3: Codigo Latino 9

● Juego Master Mind (ABAP)● Optimizaci n de C digo - C moó ó ó Convertir un Entero en Binario (C#)

● Entrevista iron man● Manejar Archivos de configuraci n o .inió de Window$ (Python)

● Fundamento de los ataques por desbordamiento de Buffer [FADB 0-1] (C – Assembly)

● Entrevista rob1104● Componente para captura de fechas (Java)

● Devolver valores (Assembly)● Miniservidor WEB en FASM (Assembly)● Exportar DB a plano (Visual FoxPro)● Juego de la Vibora (Visual Basic)

Page 4: Codigo Latino 9

Juego Master Mind

Por Blag http://atejada.blogspot.comHice un juego al éstilo de Master Mind, que es donde la PC piensa en el orden de 5 números y nosotros tenémos que adivinar cuál es... Claro que el sistema nos indica si las posiciones que ingresamos son correctas o incorrectas.

Primero comencé con un simple Dynpro...

Luego, escribí el código fuente... REPORT ZABAP_MIND_GAME. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* * CONSTANTS                                                       * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* CONSTANTS: line_length TYPE i VALUE 254. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* * TYPES                                                                  * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* TYPES: BEGIN OF ty_rand_table,        value(1) TYPE c,        END OF ty_rand_table.  *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* * INTERNAL TABLES                                           * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* DATA: t_rand_table TYPE STANDARD TABLE OF ty_rand_table,       t_user_table TYPE STANDARD TABLE OF ty_rand_table,       t_game_lines TYPE TABLE OF tline­tdline, 

Page 5: Codigo Latino 9

      data_rand TYPE REF TO data,       data_lines TYPE REF TO data. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* * FIELD­SYMBOLS                                               * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* FIELD­SYMBOLS: <fs_rand_table> LIKE LINE OF t_rand_table,                <fs_user_table> LIKE LINE OF t_user_table,                <fs_rand_value> LIKE LINE OF t_rand_table. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* * VARIABLES                                                        * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* DATA: custom_container TYPE REF TO cl_gui_custom_container,       text_editor TYPE REF TO cl_gui_textedit,       w_ucomm TYPE sy­ucomm,       ran_int TYPE qf00­ran_int,       flag TYPE c,       counter TYPE c,       gv_line TYPE string,       button_count TYPE c,       xtext TYPE tline­tdline,       game_win TYPE string,       game_counter TYPE string. DATA: message_one TYPE string,       message_two TYPE string,       message_three TYPE string,       message_four TYPE string,       message_five TYPE string. DATA: gv_one TYPE c,       gv_two TYPE c,       gv_three TYPE c,       gv_four TYPE c,       gv_five TYPE c. DATA: gv_flag_one TYPE c,       gv_flag_two TYPE c,       gv_flag_three TYPE c,       gv_flag_four TYPE c,       gv_flag_five TYPE c.  DATA: gv_user_one TYPE c,       gv_user_two TYPE c,       gv_user_three TYPE c,       gv_user_four TYPE c,       gv_user_five TYPE c. *­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *   START­OF­SELECTION                                 * *­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* START­OF­SELECTION.   CALL SCREEN 0100. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *&      Form  call_editor                                          * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* FORM call_editor.  IF text_editor IS INITIAL.     CREATE OBJECT custom_container       EXPORTING 

Page 6: Codigo Latino 9

        container_name = 'CUSTOM_CONTROL'       EXCEPTIONS         cntl_error = 1         cntl_system_error = 2         create_error = 3         lifetime_error = 4         lifetime_dynpro_dynpro_link = 5.    CREATE OBJECT text_editor       EXPORTING         wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position         wordwrap_position = line_length         wordwrap_to_linebreak_mode = cl_gui_textedit=>true         parent = custom_container       EXCEPTIONS         error_cntl_create = 1         error_cntl_init = 2         error_cntl_link = 3         error_dp_create = 4         gui_type_not_supported = 5         others = 6.     CALL METHOD text_editor­>set_readonly_mode       EXPORTING readonly_mode = 1.   ENDIF.  PERFORM get_randoms. ENDFORM. *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *&      Form  get_randoms                                       * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* FORM get_randoms.  CREATE DATA data_rand TYPE ty_rand_table.   ASSIGN data_rand­>* TO <fs_rand_table>.  WHILE flag EQ space.     CALL FUNCTION 'QF05_RANDOM_INTEGER'          EXPORTING               ran_int_max = 5               ran_int_min = 1          IMPORTING               ran_int = ran_int          EXCEPTIONS               invalid_input = 1               OTHERS = 2.    READ TABLE t_rand_table ASSIGNING <fs_rand_value>     WITH KEY value = ran_int.     IF sy­subrc NE 0.       <fs_rand_table>­value = ran_int.       APPEND <fs_rand_table> TO t_rand_table.       counter = counter + 1.       IF counter EQ 5.         flag = 'X'.       ENDIF.     ENDIF.   ENDWHILE.  game_counter = 1. ENDFORM.                    " get_randoms 

Page 7: Codigo Latino 9

*&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *&      Form  validate_game                                    * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* FORM validate_game.  LOOP AT t_rand_table ASSIGNING <fs_rand_value>.     IF gv_one IS INITIAL.       gv_one = <fs_rand_value>­value.     ELSEIF gv_two IS INITIAL.       gv_two = <fs_rand_value>­value.     ELSEIF gv_three IS INITIAL.       gv_three = <fs_rand_value>­value.     ELSEIF gv_four IS INITIAL.       gv_four = <fs_rand_value>­value.     ELSEIF gv_five IS INITIAL.       gv_five = <fs_rand_value>­value.     ENDIF.   ENDLOOP.  CLEAR: gv_user_one,gv_user_two,gv_user_three,          gv_user_four,gv_user_five.  LOOP AT t_user_table ASSIGNING <fs_user_table>.     IF gv_user_one IS INITIAL.       gv_user_one = <fs_user_table>­value.     ELSEIF gv_user_two IS INITIAL.       gv_user_two = <fs_user_table>­value.     ELSEIF gv_user_three IS INITIAL.       gv_user_three = <fs_user_table>­value.     ELSEIF gv_user_four IS INITIAL.       gv_user_four = <fs_user_table>­value.     ELSEIF gv_user_five IS INITIAL.       gv_user_five = <fs_user_table>­value.     ENDIF.   ENDLOOP.  CLEAR: game_win.   IF gv_one EQ gv_user_one.     message_one = 'First is Ok!'.     game_win = game_win + 1.   ELSE.     message_one = 'First is Wrong!'.     game_win = game_win ­ 1.   ENDIF.   IF gv_two EQ gv_user_two.     message_two = 'Second is Ok!'.     game_win = game_win + 1.   ELSE.     message_two = 'Second is Wrong!'.     game_win = game_win ­ 1.   ENDIF.   IF gv_three EQ gv_user_three.     message_three = 'Third is Ok!'.     game_win = game_win + 1.   ELSE.     message_three = 'Third is Wrong!'.     game_win = game_win ­ 1.   ENDIF. 

Page 8: Codigo Latino 9

  IF gv_four EQ gv_user_four.     message_four = 'Forth is Ok!'.     game_win = game_win + 1.   ELSE.     message_four = 'Forth is Wrong!'.     game_win = game_win ­ 1.   ENDIF.   IF gv_five EQ gv_user_five.     message_five = 'Fifth is Ok!'.     game_win = game_win + 1.   ELSE.     message_five = 'Fifth is Wrong!'.     game_win = game_win ­ 1.   ENDIF.   IF game_win EQ 5.     CLEAR: message_one,message_two,message_three,            message_four,message_five.     message_one = 'You win!'.     CONCATENATE 'In' game_counter 'tries'     INTO message_two SEPARATED BY space.   ELSE.     game_counter = game_counter + 1.     CLEAR: gv_flag_one,gv_flag_two,gv_flag_three,            gv_flag_four,gv_flag_five,sy­ucomm.   ENDIF. ENDFORM.                    " validate_game *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *&      Module  STATUS_0100  OUTPUT              * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* MODULE status_0100 OUTPUT.  SET PF­STATUS 'MAIN'.   SET TITLEBAR 'TITLE'.  IF flag EQ space.     PERFORM call_editor.   ELSE.    LOOP AT SCREEN.       IF screen­name EQ 'ONE' AND gv_flag_one EQ 'X'.         screen­invisible = 1.         MODIFY SCREEN.       ENDIF.       IF screen­name EQ 'TWO' AND gv_flag_two EQ 'X'.         screen­invisible = 1.         MODIFY SCREEN.       ENDIF.       IF screen­name EQ 'THREE' AND gv_flag_three EQ 'X'.         screen­invisible = 1.         MODIFY SCREEN.       ENDIF.       IF screen­name EQ 'FOUR' AND gv_flag_four EQ 'X'.         screen­invisible = 1.         MODIFY SCREEN.       ENDIF. 

Page 9: Codigo Latino 9

      IF screen­name EQ 'FIVE' AND gv_flag_five EQ 'X'.         screen­invisible = 1.         MODIFY SCREEN.       ENDIF.     ENDLOOP.     IF button_count EQ 5.      CLEAR button_count.      SHIFT gv_line LEFT DELETING LEADING space.      SPLIT gv_line AT space INTO TABLE t_user_table.      PERFORM validate_game.      xtext = gv_line.       APPEND xtext TO t_game_lines.      CLEAR gv_line.      CALL METHOD text_editor­>set_text_as_r3table       EXPORTING table = t_game_lines.    ENDIF.   ENDIF. ENDMODULE.                 " STATUS_0100  OUTPUT *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* *&  Module  USER_COMMAND_0100  INPUT   * *&­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­* MODULE user_command_0100 INPUT.  w_ucomm = sy­ucomm.  CASE w_ucomm.     WHEN 'BACK' OR 'CANCEL' OR 'EXIT'.       SET SCREEN 0.       EXIT.     WHEN 'ONE'.       CONCATENATE gv_line '1' INTO       gv_line SEPARATED BY space.       button_count = button_count + 1.       gv_flag_one = 'X'.     WHEN 'TWO'.       CONCATENATE gv_line '2' INTO       gv_line SEPARATED BY space.       button_count = button_count + 1.       gv_flag_two = 'X'.     WHEN 'THREE'.       CONCATENATE gv_line '3' INTO       gv_line SEPARATED BY space.       button_count = button_count + 1.       gv_flag_three = 'X'.     WHEN 'FOUR'.       CONCATENATE gv_line '4' INTO       gv_line SEPARATED BY space.       button_count = button_count + 1.       gv_flag_four = 'X'.     WHEN 'FIVE'.       CONCATENATE gv_line '5' INTO       gv_line SEPARATED BY space.       button_count = button_count + 1.       gv_flag_five = 'X'.   ENDCASE. ENDMODULE.                 " USER_COMMAND_0100  INPUT 

Page 10: Codigo Latino 9

Finalmente, tomé algunos pantallazos -;)

Espero que les guste -:) Saludos, Blag

Page 11: Codigo Latino 9

Optimización de Código - Cómo Convertir un Entero en Binario

Por JuanK http://juank.black-byte.comEl título de este post debería ser realmente: � Cómo formatear una cadena para mostrar un entero en formato binario� & pero creanme que nadie lo buscaría así en un buscador :P.

Bien esto parece ser un problema recurrente alrededor de los foros en internet, existen muchas soluciones diferentes a este problema, incluso hay algunos lenguajes que ya incluyen soporte para hacer esto fácilmente, el CLR no se caracteriza por tener una funcionalidad fácil de utilizar sin embargo en este artículo exploraremos varias soluciones (desde luego no todas )posibles hasta llegar a la solución ideal que espero les sea de provecho a todos.

Estas son las opciones que exploraremos, son básicamente 2.

La primera opción no requiere de mucho análisis pero tiene sus inconvenientes digamos menores. La

segunda opción es la que más nos importa, aprenderemos a deducir el algoritmo a implementarlo y

subsecuentemente lo iremos optimizando hasta lograr una versión digna de un excelente programador:

1. Convertir con BitVector32 (mala solución pero rápida de implementar) 2. Convertir creando un algoritmo eficiente

• Utilizando string • Utilizando StringBuilder • Utilizando punteros con código inseguro

1. CONVERTIR CON BITVECTOR32 

Esta es la solución más rápida al problema, pero en mi opinión la menos profesional& .

BitVector32 es una colección especializada que se encuentra en:

System.Collections.Specialized

Esta clase provee una estructura simple que almacena valores boleanos que representan un entero de 32 bit. Qué qué?

Ok esta explicación no necesariamente es clara para todos, hagamoslo muy simple veamos un entero de 32 bits, imaginemos que en memoria se ve así:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

Es decir cada casilla representa un bit, para completar asi 32 bits.

Bien entonces esto a final de cuentas es una coleccion bits, es decir en cada � celda� podemos tener dos valores posibles 1 o 0& true o false.

Bien eso es lo hace BitVector toma un entero y lo permite manejar como un array de booleanos.

El método ToString() permite convertir todo esto a 1s y 0s para poder ver los valores de cada � celda� en su representación numérica, sin embargo esto tiene un inconveniente pues si utilizamos

Page 12: Codigo Latino 9

elObjetoBitVector.ToString() recibiremos algo así como esto:

BitVector32{00000000000000000000000001101111}

Nos sobra algo al principio y al final& a nosotros solo nos interesan los datos binarios así que la solución es hacer un substring de la parte de la cadena que nos interesa, finalmente el código quedaría así:

public static string EB_BitVector32(Int32 entero){    BitVector32 bv = new BitVector32(entero);    return bv.ToString().Substring(12, 32);} 

Esto nos produciría este resultado similar a:

00000000000000000000000001101111

2. CONVERTIR CREANDO UN ALGORITMO EFICIENTE 

Ahora si entremos en materia hagamos el algoritmo.

Una de las primeras ideas que a uno se le viene a la mente es utilizar el conocido algoritmo que nos permite convertir un numero decimal a base 2, para el que no lo recuerde o no lo conozca: es un algoritmo que toma como base divisiones anidadas del valor entre 2 y recupera los residuos. En este link tienen una explicación detallada al respecto: Decimal a Binario

Sin embargo dicho algoritmo puede ser ineficiente para nuestro gusto.

Retomemos conceptos como puntos clave que nos permitan llegar a un algoritmo óptimo:

1. Básicamente un entero es un arreglo de 4 bytes (32 bits) 2. Por cada bit se debe producir su equivalente como cadena (� 0 , � 1 ) según si el bit esta″ ″

prendido(1) o apagado(0) 3. Podemos acceder a todos los bit como un arreglo de boolean a traves de BitVector32, pero en

ese caso la solúción sería aún más lenta que utilizando la propuesta inicial que usa BitVector32 4. Hay que encontrar el mecanismo adecuado para recorrer los bit

De los conceptos clave tenemos que los dos primeros nos son utiles, el tercero no nos aporta nada nuevo y el cuarto es nuestra necesidad más inmediata: Averiguar como recorrer los bit sin necesidad de usar BitVector32.

Lo primero que me salta a la mente es usar operadores binarios especialmente corrimientos de bit (<<) y and (&) para las máscaras.

Veamos un poco de teoría acerca de lo que haremos.

1. Crear un bucle e 32 ciclos 2. Leemos siempre el valor del primer bit del entero de 32 bit, esto lo podemos hacer efectuando

un and binario (&) del entero con un numero que tenga el primer bit prendido unicamente, es decir con : 0×80000000 (es decir 2147483648 )& porqué este número? bueno coloquemos este

Page 13: Codigo Latino 9

0×80000000 en nuestro arreglo de 32 bits:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

8 0 0 0 0 0 0 0

Cada 4 bits representan uno de los digitos hexa, de esta forma el 0×8 esta representado por los primeros 4 bits, en efecto 1000 = 0×8, así que si se fijan en nuestro arreglo de bits solo tenemos un bit prendido, de tal forma que cualquier cosa que haga & con 0×80000000 solo podría llegar a tener prendido el bit 1, así podemos hallar que valor tiene el bit 1 de un número dado ya que si ese bit esta en 0 al hacer and quedaria en 0, mientras que si esta en 1 al hacer and quedaria en uno nuevamente. Concretando, cuando hacemos un and entre dos enteros y uno de los enteros es 0×80000000 el resultado siempre sera el valor del primer bit del otro entero. ( espero haber sido claro).

3. En cada iteración corremos 1 bit posición a la izquierda (<< 1), de tal forma que el primer bit es reemplazado por el bit siguiente

4. Se regresa al paso 2

IMPLEMENTACION CRUDA UTILIZANDO String

Este es el código resultante de la implementación más simpe del algoritmo:

public static string EB_String(int entero){    //La máscara y el # de iteraciones    const uint mascara = 0x80000000;    const int iteraciones = 32;    //el contador y el resultado    int contador = 0;    string resultado = "";    //Se recorren los 32 bit    while (contador++ < iteraciones)    {        /*Si el entero and la mascara = 0 quiere decir         *que el bit 1 esta apagado*/        if ((entero & mascara) == 0)            resultado += "0";        else            resultado += "1";        /*correr un bit a la izquierda para poner         *el siguiente bit en la posicion del primero*/        entero = entero << 1;    }    return resultado;} 

OPTIMIZACIÓN DE CÓDIGO UTILIZANDO StringBuilder

La implementación anterior es suceptible de una sencilla mejora utilzando StringBuilder ya que al ser string un tipo inmutable , las recurrentes concatenaciones generadas al utilizar masivamente el método

Page 14: Codigo Latino 9

sobrecargarian el GC, sin contar el overhead producido por las frecuentes reservas de memoria (1 adicional por cada cambio al string). StringBuilder se encuentra en el namespace System.Text.

Código optimizado utilizando StringBuilder:

public static string EB_StringBuilder(int entero){    //La máscara y el # de iteraciones    const uint mascara = 0x80000000;    const int iteraciones = 32;    //el contador y el resultado    int contador = 0;    StringBuilder resultado = new StringBuilder(iteraciones);

    //Se recorren los 32 bit    while (contador++ < iteraciones)    {        /*Si el entero and la mascara = 0 quiere decir         *que el bit 1 esta apagado*/        if ((entero & mascara) == 0)            resultado.Append('0');        else            resultado.Append('1');        /*correr un bit a la izquierda para poner         *el siguiente bit en la posicion del primero*/        entero = entero << 1;    }    return resultado.ToString();} 

OPTIMIZACIÓN DE CÓDIGO UTILIZANDO PUNTEROS ­ código unsafe

Aunque StringBuilder ya proporciona una mejora muy importante, dadas las características de nuestro problema(concatenacion uno a uno) resulta mucho más idoneo generar código que utilice punteros. Es importante tener en cuenta que para que este código funcióne se requiere modificar las propiedades del proyecto para que admita código unsafe.

Esta es la versión básica con manejo de apuntadores:

public static unsafe string EB_Unsafe(int entero){    const uint mascara = 0x80000000;    const int iteraciones = 32;

    int contador = 0;

    //Se reservan 32 posiciones y uno adicional para     //terminacion en null    char* resultado = stackalloc char[iteraciones + 1];    //puntero de trabajo    char* aux = resultado;

    

Page 15: Codigo Latino 9

    while (contador++ < iteraciones)    {        if ((entero & mascara) == 0)            *aux = '0';        else            *aux = '1';

        //Mover el puntero una posicion dentro de la cadena        aux++;

        entero = entero << 1;    }    return new string(resultado);} 

Esta es la versión final de � bonus� totalmente optimizada para velocidad de procesamiento, es

levemente diferente de la anterior para realizar la menor cantidad de validaciones posibles y para que ignore los 0s a la izquierda, lo cual la hace excepcionalmente rápida en la mayoría de los casos. Revísenla& :

public static unsafe string EB_Unsafe_Opt(int entero){    const uint mascara = 0x1;    const int iteraciones = 32;

    char* resultado = stackalloc char[iteraciones + 1];    char* aux = resultado + iteraciones ­ 1;    do    {        if ((entero & mascara) == 0)            *(aux­­) = '0';        else            *(aux­­) = '1';

        entero = entero >> 1;    } while (entero != 0);    return new string(++aux);} 

Si alguién tiene una solución mejor por favor no dude en compartirla!!

En unos días publicare un programa especialmente diseñado para medir la velocidad de cada una de estas altenativas& les adelanto que las diferencias de tiempo van casi hasta de 20 o 30 veces más velocidad.

Happy Learning!!!

OOOHH OLvidaba decirles Si quieren pueden usar:

System.Convert.ToString(elValor, 2); 

jajajajaja, bueno el ejercicio que hicimos produce un resultado 30% más rapido.

Page 16: Codigo Latino 9

iron man fue conocido en su época como SoloCodigo, es el administrador de adivinen cuál foro..... pues sí adivinaron, SoloCodigo; tengo el placer de pertenecer a esta grandiosa comunidad desde el año 2004, esta fue formada por él en el 2002, hace más de 6 años (primer post).

1) ¿De donde eres?

Barcelona, España.

2) ¿Hace cuánto que comenzaste a programar?

Los primeros pasos fueron con el ZX Spectrum 48 K y el Amstrad CPC 6128, que incluía un manual de Basic. De eso hace veintimuuuchos años.

3) ¿Cuáles son tus lenguajes de programación

favoritos?

No tengo un lenguaje favorito, creo que hay lenguajes más adecuados que otros dependiendo de los requisitos y la misión del programa. Por mi trabajo, actualmente PHP es el que más utilizo.

4) ¿Cuáles son tus programas favoritos de

Diseño?

Photoshop, Adobe Illustrator, Swish Max2

5) ¿Qué te inspiró a ser programador?

Supongo que la posibilidad de CREAR algo. De niño siempre me atrajeron los juegos de construcción como Tente o Mecano. En el fondo, programar es un juego de construcción, con la ventaja de que puedes construir una pequeña casa o un rascacielos invirtiendo el mismo dinero. Obviamente la diferencia está en el tiempo (y mucha gente opinará, con algo de razón, que el tiempo es dinero), pero si lo tienes, no hay límites. No es maravilloso? :)

6) ¿Cuéntanos un poco acerca de tu compañía?

No hay mucho que contar, soy trabajador autónomo, aunque me gustaría crear una compañía algún día :)

7) ¿Qué opinas de la escena de programadores

en Latinoamérica?

Creo que hay mucho talento y no todo el mundo tiene la posibilidad de demostrarlo. Hacen falta más medios para poner el conocimiento al alcance de la gente. SoloCodigo es una pequeña muestra de que existe talento e interés en la programación entre la comunidad hispanohablante. Creo que aún podemos hacer mucho más.

8) ¿Cuáles son tus nuevos proyectos?

Actualmente estoy trabajando en el proyecto Weeo! Me perdonarás que no diga nada más por ahora, verdad Edo? :P

9) ¿Que te gustaría ver en los próximos años en

el mundo de la programación?

No lo se, me parece muy complicado hacer cualquier tipo de previsión. En algún momento la idea de una sola persona o de un pequeño grupo puede llegar a tener tanta influencia como el avance de la tecnología. Bueno, puestos a pedir, me gustaría ver algún aparato que capte las órdenes del cerebro y nos permita programar sin teclado :P

10) ¿Cuál es tu mensaje final para la

comunidad?

Simplemente animar a todo el mundo interesado en la programación a documentarse todo lo que puedan y a no rendirse ante las dificultades, que siempre las hay pero sirven de motivación. Y por supuesto invitarles a visitar solocodigo.com y a que sigan disfrutando de Código Latino.

Gracias y un saludo ;)

Page 17: Codigo Latino 9

Manejo de Archivos de Configuración o .ini de Window$

Por RadicalEd http://radicalpython.blogspot.comMuchas de las aplicaciones actuales utilizan archivos de configuración para guardar datos de inicialización, hoy veremos como manejar esos archivos desde Python.

Una manera poco ortódoxa de hacerlo sería abrir el archivo y por medio de expresiones regulares comenzar a extraer los datos de las clave:valor que se necesitan manejar; lo bueno es que en Python tenemos baterías incluidas y de todos los módulos que están en el repositorio tenemos uno llamado ConfigParser, que nos servira para manejar un archivo de configuración.

Tengamos en cuenta el siguiente archivo config.cfg:[LLAVE1]CLAVE1=VALOR1CLAVE2=VALOR2

[LLAVE2]CLAVE3:VALOR3CLAVE4:VALOR4

Como vemos se puede manejar � clave=valor� o � clave:valor� , ahora manipulemos este archivo por medio de Python con el módulo re y ConfigParser.

Ejemplo módulo re#!/usr/bin/env python #­*­ coding:iso8859­1 ­*­ import re #Variable para indexarle los datos del archivo strarchi = '' #Abrimos el archivo archi = open('config.cfg', 'r') #Recorremos el archivo for linea in archi.readlines():       #Se lo asignamos a la variable       strarchi = strarchi + linea #Cerramos el archivo archi.close() 

 #Digitamos la clave a buscar buscar = raw_input('Digite clave a buscar: ') 

#Con el método search hacemos la búsqueda try:     m = re.search('(?<=' + buscar + '[:­=])\w+', strarchi)     print m.group(0) except:     print 'No existe la clave'

Page 18: Codigo Latino 9

NOTA: Realmente no quiero saber cómo hago para adicionar el dato en la clave :P

Ejemplo módulo ConfigParser:#!/usr/bin/env python #­*­ coding:iso8859­1 ­*­ import ConfigParser#Se crea un objeto ConfigParsercfg = ConfigParser.ConfigParser() #Abrimos el archivocfg.readfp(file('config.cfg')) #Obtenemos los valores de las Claves utilizadas, #pasando como primer parámetro la Llave a la que pertenececlave1 = cfg.get('LLAVE1', 'CLAVE1') clave2 = cfg.get('LLAVE1', 'CLAVE2') clave3 = cfg.get('LLAVE2', 'CLAVE3') clave4 = cfg.get('LLAVE2', 'CLAVE4') print clave1+" "+clave2+" "+clave3+" "+clave4 

Aja y qué estamos haciendo, sencillo, lo primero que debemos hacer es importar el módulo del ConfigParserimport ConfigParser

Luego debemos crear un objeto tipo ConfigParser, para acceder a los datos del archivocfg = ConfigParser.ConfigParser()Por último lo que debemos hacer es leer las clave:valor del archivo por medio del método get:

get( section, option )clave1 = cfg.get('LLAVE1', 'CLAVE1') Aja muy y lindo todo eso y qué?, ahora cómo hacemos para escribir sobre el archivo???

Para eso tenemos el metodo set y write:

set( section, option, value )

write( fileobject )

Ejemplo 2 Módulo ConfigParser:#!/usr/bin/env python #­*­ coding:iso8859­1 ­*­ import ConfigParser#Se crea un objeto ConfigParsercfg = ConfigParser.ConfigParser() #Abrimos el archivocfg.readfp(file('config.cfg')) #Obtenemos los valores de las Claves utilizadas, #pasando como primer parámetro la Llave a la que pertenececlave1 = cfg.get('LLAVE1', 'CLAVE1') clave2 = cfg.get('LLAVE1', 'CLAVE2') clave3 = cfg.get('LLAVE2', 'CLAVE3') clave4 = cfg.get('LLAVE2', 'CLAVE4') print clave1+" "+clave2+" "+clave3+" "+clave4 

Page 19: Codigo Latino 9

#Vamos a ingresar datos sobre la CLAVE1 de la LLAVE1cfg.set('LLAVE1', 'CLAVE1', 'NUEVO VALOR1') #Creando una nueva clavecfg.set('LLAVE1', 'CLAVE3', 'VALOR3') #Se abre el archivo para indexar los nuevos datos archi = open('config.cfg', 'w') plano.cfg.write(archi) archi.close() 

Se nota la diferencia en cantidad de líneas y en la sencillez de extracción de datos.Gracias Chao

Page 20: Codigo Latino 9

Fundamentos de los Ataques por Desbordamiento de BufferPor m0skit0 http://fr33kk0mpu73r.blogspot.com

Esta será una serie de varios capítulos con la ayuda de nuestro amigo m0skit0

[FADB 0. Introducción]Para entender esta serie hace falta un conocimiento del lenguaje C y ensamblador. No hace falta ser un experto ni mucho menos, los artículos están muy detallados. Para cualquier duda, simplemente ¡comentad!

Un desbordamiento de buffer ocurre cuando escribimos en un buffer una cantidad de datos mayor de la que es capaz de almacenar dicho buffer. Cuando esto ocurre, la memoria que se encuentra después del final del buffer se sobreescribe con los datos que no caben en éste.

Dado que para entender de qué trata y cómo funciona un desbordamiento de buffer hay que referirse a niveles muy bajos de programación (ensamblador) que implican diferencias entre arquitecturas y sistemas operativos, he decidido centrarme en Linux (gcc 3.2 y gdb 5.2.1-2mdk) corriendo sobre Intel 386 (o superior pero 32 bits: 486, Pentium, Celeron, AMD...). Esta decisión está basada en que la arquitectura IA-32 es la más ampliamente disponible y que cualquier distribución de Linux (disponibles casi todas gratuitamente y descargables de Internet) tiene incorporadas todas las herramientas que vamos a necesitar, a parte de la inherente robustez de este sistema operativo para realizar tareas de programación.

Empezaré haciendo un repaso de algunas características de la arquitectura de IA-32 de Intel: funcionamiento de la pila con las instrucciones PUSH y POP, las llamadas a procedimientos con las instrucciones CALL y RET, el paso de parámetros por pila y las variables locales en la pila.

Una vez aclarados estos puntos, pasaremos a las técnicas que permiten explotar un desbordamiento de buffer: primero, abordaremos la sobreescritura directa de la dirección de retorno de un procedimiento; después con un desbordamiento de buffer en vez de directamente. Llegados a este punto introduciremos la llamada al sistema execve() que nos permite sustituir el proceso actual por otro. Segundo, ejecutaremos una cadena de caracteres (string en C) como si fuera código, directamente y con desbordamiento de buffer. Tercero, veremos un ejemplo de cómo conseguir hacer lo que hemos visto con un programa que tan sólo recibe una entrada de texto.ahora se usa el paso de parámetro por registros (que es más rápido pero limitado al número de registros y a su tamaño). EBX es el puntero a la cadena de caracteres que representa el comando, ECX es el puntero al array de argumentos y EDX el puntero al entorno (en nuestro caso NULL).

Page 21: Codigo Latino 9

[FADB 1. La Pila]Un programa se divide generalmente en tres partes: el código, los datos y la pila. La parte de código contiene las instrucciones a ejecutar por parte de la CPU y suele ser de sólo lectura. La sección de datos contiene los datos iniciales del programa, así como el espacio reservado para las variables declaradas globales. La pila se utiliza para guardar valores temporales (como las variables locales).

Las instrucciones PUSH y POP de las CPU Intel x86 permiten hacer uso automático de la pila. PUSH mete un dato en la pila y POP saca un dato de la pila. Un registro llamado ESP (Extended Stack Pointer) contiene la dirección actual de la cima de la pila. La pila funciona creciendo hacia las direcciones bajas de memoria.

Si por ejemplo tenemos el siguiente código:

PUSH EAX PUSH EBX POP EBX POP EAX 

con ESP = 0x00000100 (0x significa que el número que sigue está dado en hexadecimal), EAX = 0xAABBAABB y EBX = 0x11AA11AA.

Al ejecutar la primera instrucción (PUSH EAX), la CPU decrementa ESP en 4 (siempre se decrementan 4, que corresponden a 4 posiciones de memoria, es decir, 4 bytes, una palabra de 32 bits), con lo que ESP = 0x000000FC, y copia EAX en la dirección apuntada por ESP, es decir 0x000000FC. A este proceso es lo que llamamos meter en la pila. Por lo tanto la memoria queda tal que así:

0x0000010 -> ?? 0x000000FF -> AA 0x000000FE -> BB 0x000000FD -> AA 0x000000FC -> BB 0x000000FB -> ??

Las CPUs Intel x86 funcionan en low-endian, es decir, que el byte menos significativo se almacena en la dirección de memoria más baja. Con la siguiente instrucción, PUSH EBX, ocurre exactamente los mismo. Tenemos que ESP = 0x000000F8 y la pila queda como sigue:

0x00000100 -> ?? 0x000000FF -> AA 0x000000FE -> BB 0x000000FD -> AA 0x000000FC -> BB

Page 22: Codigo Latino 9

0x000000FB -> 11 0x000000FA -> AA 0x000000F9 -> 11 0x000000F8 -> AA 0x000000F7 -> ?? Ahora bien, la instrucción siguiente, POP EBX, realiza el proceso contrario: primero extrae (4 bytes) lo apuntado por ESP al registro especificado, en este caso EBX = 11AA11AA, y suma 4 a ESP, que nos deja con ESP = 0x000000FC y el mismo mapa de memoria que arriba. Esto se le denomina sacar de la pila. Los datos que se han sacado de la pila no son borrados, sólo se modifica ESP. POP EAX hace lo mismo: copia los 4 bytes apuntados por ESP (0xAABBAABB) a EAX, y luego suma 4 a ESP, que se queda como ESP = 0x00000100.

A la pila se la denomina una estructura de datos LIFO (Last Input First Output), es decir, el útlimo en meterse es el primero en salir. Efectivamente, el último PUSH fue el de EBX y el primer POP el de éste. En caso de que el código fuera

PUSH EAX PUSH EBX POP EAX POP EBX 

acabaríamos con EAX = 11AA11AA y EBX = AABBAABB, es decir, intercambiaríamos los valores de ambos registros. Como su nombre indica (LIFO), el primer dato en sacarse es el último en haberse metido.

Page 23: Codigo Latino 9

rob1104 es uno de los grandes programadores que tengo el placer de conocer, es moderador del foro de programación en TrucosWindows, esto fue lo que nos regalo para la entrevista.

1) ¿De donde eres?

Monterrey, Nuevo León. México, una de las mas importantes y bellas ciudades de mi país

2) ¿Hace cuánto que comenzaste a programar?

Hace 8 años, empeze sin saberlo, ya que entré a una escuela para estudiar una carrera tecnica de computación, pero entré algo avanzado y me adelantaron un año, directamente a FoxPro xD

3) ¿Cuáles son tus lenguajes de programación

favoritos?

Estoy enamorado de la tecnologia .NET, increible que haya sido desarrollada por microsoft, mis favoritos actualmente son: C#, vb.net, java y php

4) ¿Cuáles son tus programas favoritos de

Diseño?

No se me da mucho el diseño, pero tengo instalados: Adobe photoshop cs3, fireworks cs3 y corel draw x4

5) ¿Qué te inspiró a ser programador?

Sin lugar a dudas los videojuegos, desde la primera vez que jugue Super Mario Bros de NES me dio curiosidad de porque se movia el monito al presionar el pad del control.

6) ¿Cuéntanos un poco acerca de tu compañía?

Actualmente trabajo como ingeniero de soporte, no estoy al 100% programando, pues somos una compañia global: mantenimiento, soporte, diseño, programacion, redes, etc... y pues dirigo un poco de todo, pero mi fuerte es la programacion de

aplicaciones de escritorio.

7) ¿Qué opinas de la escena de programadores

en Latinoamérica?

Para ser sincero pienso que somos minoria, pero poco a poco vamos naciendo mas programadores latinoamericanos, tenemos que demostrar que no necesitamos tener el ingles como lengua natal para dominar la programacion, y asi las empresas pongan casas desarrolladoras en nuestros paises.

8) ¿Cuáles son tus nuevos proyectos?

Al cliente lo que pida, ahorita esta muy de moda la programación web, tenemos algunas paginas dinamicas escolares, sistemas en red para tiendas, y portales para pequeñas empresas, todo bajo ambiente web.

9) ¿Que te gustaría ver en los próximos años en

el mundo de la programación?

Una mayor interactividad entre el programa y el usuario, eliminar las clasicas interfaces de botones y textos, que se pueda controlar el software a traves de mas partes del cuerpo, como la boca, ojos o incluso la mente, en fin... solo el futuro lo dirá..

10) ¿Cuál es tu mensaje final para la

comunidad?

Nunca se den por vencidos, por mas lejanos o dificiles que sean sus sueños y proyectos siempre luchen para salir adelante, en la vida nada es facil y aquel que se queda estancado nunca logrará sobresalir.

Saludos

Page 24: Codigo Latino 9

Componente para captura de fechasPor shakka http://mbrenes.blogspot.com

Si usamos NetBeans para diseñar la interfaz de usuario, veremos que desde el editor del IDE no podremos editar el código correspondiente a la inicializacion de la instancia, pero evidentemente si lo podemos hacer cerrando NB y editando el código fuente o bien, sin salir del NB, damos click derecho sobre el control y vamos a Customize Code.

Una vez agregado JCalendar al classpath del proyecto(no lo voy a utilizar desde el diseñador esta vez xD) me he puesto a trastear con el y utilizarlo en una aplicacion donde el usuario debe llenar un campo de texto de un formulario respetando un formato para la fecha, pero el usuario no debera editar directamente este campo si no que seleccionara la fecha presionando un boton que cargara una ventana tipo pop up, en la cual vera un calendario y un boton de aceptar(que al ser presionado, guardara los datos de la fecha elejida y que posteriormente podemos obtener mediante los metodos que provee la clase(una que me he creado), posteriormente cerrara la ventana). /*  * Clase, uso de JCalendar como una ventana tipo Pop Up  * Copyright (C) 2008 Moises Brenes, http://mbrenes.blogspot.com  *   * This program is free software; you can redistribute it and/or modify  * it under the terms of the GNU General Public License as published by  * the Free Software Foundation; either version 2 of the License, or  * (at your option) any later version.  *  * This program is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  * GNU General Public License for more details. 

Page 25: Codigo Latino 9

 *  * You should have received a copy of the GNU General Public License  * along with this program; if not, write to the Free Software  * Foundation, Inc., 59 Temple Place ­ Suite 330, Boston, MA 02111­1307, USA.  *  * Any non­GPL usage of this software or parts of this software is strictly  * forbidden.  */ 

package datepicker; 

/**  *  * @author shakka  */  public class CDatePicker extends javax.swing.JDialog {     private com.toedter.calendar.JCalendar jCal;     private javax.swing.JPanel pnlDatePicker;     private javax.swing.JButton btnAccept;     private String year;     private String month;     private String day; 

public CDatePicker(java.awt.Frame parent) {     super(parent, true);     initComponents();     initExtra(); } 

public static void main(String args[]) {     java.awt.EventQueue.invokeLater(new Runnable()     {       public void run()       {         CDatePicker dialog = new CDatePicker(new javax.swing.JFrame());          dialog.addWindowListener(new java.awt.event.WindowAdapter()         {           public void windowClosing(java.awt.event.WindowEvent e)           {             System.exit(0);           }         });            dialog.setVisible(true);       }     });   } 

Page 26: Codigo Latino 9

  private void initComponents()   {     setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);     setSize(290,275);     setModal(true);     setTitle("Calendario.");     setResizable(false);     setLayout(null); 

    /* Centrar pantalla */     setLocationRelativeTo(null); 

    pnlDatePicker = new javax.swing.JPanel();     pnlDatePicker.setLayout(null);     pnlDatePicker.setBorder(javax.swing.BorderFactory.createEtchedBorder());     pnlDatePicker.setBounds(2, 2, 278, 250);     add(pnlDatePicker); 

    jCal = new com.toedter.calendar.JCalendar();     jCal.setWeekOfYearVisible(false);     jCal.setBounds(3, 2, 271, 204);     pnlDatePicker.add(jCal);      btnAccept = new javax.swing.JButton();     btnAccept.setText("Aceptar");     btnAccept.setMnemonic('A');     btnAccept.setBounds(3, 206, 271, 32);     pnlDatePicker.add(btnAccept);     btnAccept.addActionListener(new java.awt.event.ActionListener()     {       public void actionPerformed(java.awt.event.ActionEvent ev)       {         btnAccept_Click();       }     } );   } 

  private void initExtra()   {     year = new String("");     month = new String("");     day = new String("");   } 

  public String getYear()   {     return year;   } 

  public String getMonth()   {     return month;   }   public String getDay() 

Page 27: Codigo Latino 9

  {     return day;   }    public void btnAccept_Click()   {           year = Integer.toString(jCal.getCalendar().get(java.util.Calendar.YEAR));     month = Integer.toString(jCal.getCalendar().get(java.util.Calendar.MONTH) + 1);     day = Integer.toString(jCal.getCalendar().get(java.util.Calendar.DATE));     dispose();   } 

}

En este método de la clase, en la versión que utilizo en la vida real hago uso de una clase propia(CPadding) que rellena con ceros a la izquierda los datos miembro de la clase, ya que lo ocupo de esa manera. public void btnAccept_Click() {         CPadding yearPad = new CPadding(Integer.toString(jCal.getCalendar().get(java.util.Calendar.YEAR)));   CPadding monthPad = new CPadding(Integer.toString(jCal.getCalendar().get(java.util.Calendar.MONTH) + 1));   CPadding dayPad = new CPadding(Integer.toString(jCal.getCalendar().get(java.util.Calendar.DATE))); 

  year = yearPad.padLeft('0', 4);   month = monthPad.padLeft('0', 2);   day = dayPad.padLeft('0', 2);         dispose(); 

}

Ya en el formulario, el botón que cargará la ventana que contiene el bean calendario lo hará mediante el evento típico de este componente(click). /* Evento del boton */ private void btnSel004ActionPerformed(java.awt.event.ActionEvent evt) {     /* Se crea la instancia y se hace visible */     CDatePicker dlgDate = new CDatePicker(new javax.swing.JFrame());     dlgDate.setVisible(true);      /* Cuando el usuario simplemente cierra la ventana      * con boton de cerrar del dialogo,  aunque seleccione una fecha      * la informacion que obtenemos de la fecha mediante los metodos de la clase      * estaran vacios, caso contrario cuando presiona el boton aceptar.      */     if (dlgDate.getDay().compareTo("") != 0)     {       txtCampoFecha.setText       ( 

Page 28: Codigo Latino 9

        dlgDate.getYear() + "/" + dlgDate.getMonth() + "/" + dlgDate.getDay()       );     } 

}

Mas informacion: http://www.toedter.com

Page 29: Codigo Latino 9

Devolver Valores en AssemblyPor Eternal_Idol

¿Alguna vez se preguntaron que hace la instrucción return de C\C++ y porqué estamos limitados a devolver un solo valor cuando podemos pasarle varios a una función? ¿Que es lo que hace la instrucción return? Algo muy simple que es ajustar la pila segun la llamada, darle un valor a eax y saltar a la instrucción siguiente a la que llamo a nuestra función.

Lo que nos interesa es esto __asm {     mov eax,valor 

}

En Windows el valor que devuelve una función se guarda en el registro eax; pero eax no es el único registro que existe ni mucho menos, existen 4 registros de uso general (eax,ebx,ecx y edx). eax viene de acumulador, ebx de base (no lo podemos usar para devolver nada porque Windows lo maneja), ecx de contador y edx de dato. Entonces tenemos 2 lugares más donde devolver valores de una función, como si tuvieras un return1, return2 y un return3!!.

Vamos a ver un ejemplo muy simple para empezar: #include <windows.h> void SayLong(int number) {     char Data[5];     ltoa(number,Data,10);     MessageBox(0,Data,"El Numero",0); } int mi_funcion() {     //__asm mov eax,76     return 76; } void main() {    DWORD Resultado = 0;    Resultado = mi_función();    SayLong(Resultado); 

}

Qué hace este programa?

Algo muy simple muestra con un MessageBox el valor que devuelve la función mi_funcion, pero esto nos va a servir para demostrar lo que les conte antes; descomenten la línea que comienza con __asm (le dice al compilador que escriba una o varias instrucciones de ensamblador) y comenten la que empieza con return.

Page 30: Codigo Latino 9

Qué funciona exactamente igual? Sí, sí, Windows devuelve el valor de una función en eax. Ahora vamos a lo bueno, si no existe solo eax y también tenemos 2 registros como ecx y edx eso significa que podemos devolver hasta 3 valores de una función! #include <windows.h> void SayLong(int number) {    char Data[5];    ltoa(number,Data,10);    MessageBox(0,Data,"El Numero",0); } void return1(DWORD Valor) { __asm mov eax,Valor } void return2(DWORD Valor) { __asm mov ecx,Valor } void return3(DWORD Valor) { __asm mov edx,Valor } void sin_valor(); void main() {     DWORD Valor1,Valor2,Valor3;     sin_valor();     __asm mov Valor1,eax     __asm mov Valor2,ecx     __asm mov Valor3,edx     SayLong(Valor1);     SayLong(Valor2);     SayLong(Valor3); } void sin_valor() {     return1(66);     return2(75);     return3(99); } 

Finalmente ahora viene lo bueno, creamos un array de punteros (tipo string) en una función y la utilizamos en otra: #include <windows.h> void SayLong(int number) {    char Data[5];    ltoa(number,Data,10);    MessageBox(0,Data,"El Numero",0); } void return1(DWORD Valor) { __asm mov eax,Valor } DWORD Trozear(char *str) {    DWORD Max = strlen(str);    DWORD Palabras = 0;    char **str_array = (char**)malloc(1*4); //un solo puntero a string    str_array[0] = (char*)malloc(1024);    ZeroMemory(str_array[0],1024);    for (int x = 0;x < Max;x++)    {      DWORD Pos = strlen(str_array[Palabras]); 

Page 31: Codigo Latino 9

     if (str[x] == 32)      {        Palabras++;        str_array = (char**)realloc(str_array,(Palabras+1)*4);        str_array[Palabras] = (char*)malloc(1024);        ZeroMemory(str_array[Palabras],1024);      }      str_array[Palabras][Pos] = str[x];      str_array[Palabras][Pos+1] = 0;    }    __asm    {      mov ecx,[str_array]    }    return Palabras+1; } void main() {    DWORD Palabras = 0;    char *texto = (char*)malloc(1024);    strcpy(texto,"Esta es una prueba para que separe por espacios");    Trozear(texto);    char **str_ptr;    __asm mov Palabras,eax    __asm mov [str_ptr],ecx    SayLong(Palabras);    for (int y = 0;y < Palabras;y++)    {      MessageBox(0,str_ptr[y],"Palabra",0);      free(str_ptr[y]);    }    free(str_ptr);    free(texto); 

}

Bueno, espero que les hayá gustado, sé que ya habrá algunos diciendome que podría haber usado un doble puntero en el protótipo de la función y obtener el mismo resultado; sí, pero sin saber cómo funciona. Por cierto en mi trabajo utilizé este método para devolverme otros valores de una DLL creada por una compañera, asi seguía siendo compatible (en cuanto a parámetros).

Saludos, Mariano.

Page 32: Codigo Latino 9

Mini Servidor WEB en FASMPor Enko

Requerimientos: Conocer minímamente como funcionan los socket. Conocer el lenguaje Assembly, en este caso como ensamblador se usará FASM. (http://flatassembler.net)

Este artículo se basa en dos partes, una teoríca que explica de manera sencilla como es que funciona un servidor http. Y la otra práctica, que muestra un ejemplo de un servidor en fasm.

Comencemos! Antes que nada, necesitamos primero entender como es que funciona un servidor. Cuando hacemos click en algun vínculo, o abrimos una dirección url, el cliente (IExplorer, Mozilla, Opera, Chrome, etc) se encarga de envíar una solicitud al servidor. Dicha solicitud el usuario nunca la ve, pero para poder entender el funcionamiento, vamos a continuación ver un método de cómo realizar esta solicitud manualmente usando sencillamente una consola telnet.

Podemos hacer esto abriendo una consola TELNET así:

telnet http://www.mysite.com 80

Luego ingresamos la solicitud del archivo usando el protocolo http:

GET /path/file.html HTTP/1.0 [otras cabeceras aqui] [una linea en blanco]

El servidor aceptará todo hasta que le envéemos la linea en blanco. Otro ejemplo:

GET /index.html HTTP/1.0 From: info@códigolatino.com User-Agent: HTTP_CA_FASM/1.0 [linea en blanco] Una vez recibida la solicitud, el servidor se encarga de analizarla, si el archivo solicitado existe, responde con el código de estado h200 y envía el archivo.

Page 33: Codigo Latino 9

Si el archivo no existe, responde con código de estado h404, el famoso FILE NOT FOUND. Ejemplo respuesta 404:

HTTP/1.0 404 Not Found Content-Type: text/html <html>   <body>     ARCHIVO NO ENCONTRADO   </body> </html> 

Ejemplo respuesta 200:

HTTP/1.0 200 OK Date: Fri, 31 Dec 2008 23:59:59 GMT Content-Type: text/html <html>   <body>      EL MEJOR VIOLINISTA: PAGANINI      EL MEJOR GUITARRISTA:  CACHO TIRAO      LA MEJOR REVISTA: Código LATINO   </body> </html> 

Códigos de Estado: Son códigos que envía el servidor al cliente dentro de la cabecera cada vez que responde. Los más comunes son: 200 OK: el archivo solicitado existe, y se envía 404 Not Found: el archvio no existe 301 Moved Permanently 302 Moved Temporarily 500 Server Error

Ahora que vimos como funciona el protocolo, el resto es sumamente sencillo, se puede explicar con los siguientes 7 pasos:

1. Abrimos un socket 2. Lo ponemos a escuchar 3. Esperamos una solicitud, si la hay... 4. Leemos la solicitud 5. Analizamos el archivo pedido de la url 6. Si no existe mandamos la cabecera h404 7. Si existe, mandamos la cabecera h200 seguida del envio del archivo pedido.

Lo ideal es abrir un hilo para cada solicitud, de esta manera el servidor puede analizar más pedidos en menos tiempo. Así pues, los pasos 4,5,6,7 podrían estar metidos en un hilo.

Page 34: Codigo Latino 9

A continuación, un mini servidor (3.50Kb) de ejemplo. Despues del código viene la explicación format PE Console entry start  include '%fasminc%/win32a.inc' include '%fasminc%/macro/if.inc'  MAX_QUEUE   equ 100     ;max namber of pending connections BUFFER_SIZE equ 2048    ;max size of the header sended by the client MAX_URL_SIZE equ 1024   ;max size of url in the header sended SHOW_DETAILED_MSG equ TRUE ;set TRUE if want to see the full client message  section '.data' data readable writeable     wsa     WSADATA     port    dd 80         szPause db "PAUSE",0     h404    db "HTTP/1.1 404 Not Found",13,10,"Server: EnkoHttpServer 1.0.0.0 ",               13,10,13,10,"<HTML><BODY>404 Not Found</BODY></HTML>",13,10     .size = $ ­ h404     h200    db "HTTP/1.1 200 OK",13,10,"Server: EnkoHttpServer 1.0.0.0 ",               13,10,"Allow: GET",13,10,13,10     .size = $ ­ h200     szRoot      db "D:\Documentos\Enko\Assembly\Projects\httpServer",0     szSlashes   db '/\',0     szSlash     db '\',0     szTockens   db " ",13,10,0     szError     db "ERROR: %i",13,10,0     szDot       db ".",0     szFileNotExists db "File Not Exists",13,10,0     szInt       db "%i",0     szFile      db "FILE: %s",13,10,0     szClient    db "Client IP: %s",13,10,0     szRequest   db "REQUEST: %s",13,10,0     szStatus    db "STATUS: %s",13,10,0     szString    db "%s",0     szEndLine   db 13,10,0     .size = $ ­ szEndLine     szBr        db "<br>",0     szIndex     db "index.html",0     szFileSended    db "File sended ok",13,10,0     .size = $ ­ szBr     wSocketVersion dd 0x0101     transmiteBuffer dd h200,h200.size,NULL,NULL     thread  dd ?        peer    dd ?     peerAddr sockaddr_in     sizePeerAddr dd sizeof.sockaddr_in     sock     dd ?     sock_addr   sockaddr_in     szBuffer db 32 dup ?     szIp     db 16 dup ?     

Page 35: Codigo Latino 9

section '.code' code readable executable start:     ;inti the socket     invoke  WSAStartup, [wSocketVersion], wsa        invoke  socket,AF_INET,SOCK_STREAM,NULL     mov     [sock],eax        mov     [sock_addr.sin_family], AF_INET     invoke  htons,[port]     mov     [sock_addr.sin_port],ax        mov     [sock_addr.sin_addr],NULL     invoke  bind, [sock], sock_addr,sizeof.sockaddr_in     .if eax <> 0         invoke  WSAGetLastError         cinvoke printf, szError, eax            .endif        invoke listen, [sock],MAX_QUEUE 

accepted:     ;socket listening     invoke accept, [sock],peerAddr,sizePeerAddr     mov     [peer],eax     stdcall ipToString,[peerAddr.sin_addr],szIp     cinvoke printf, szClient,szIp     ;new thread for each connection     invoke CreateThread, NULL,NULL, resolveConnection,[peer],NULL,NULL     jmp     accepted     invoke  ExitProcess,0  ;the connection manager proc resolveConnection, lpParam local lpeer: DWORD, lbuffer: DWORD, lurl: DWORD, lfile: DWORD     mov     eax, [lpParam]     mov     [lpeer],eax     cinvoke malloc, BUFFER_SIZE     mov     [lbuffer],eax     invoke  recv, [lpeer],[lbuffer],BUFFER_SIZE,0     ;if there is a message then continue     .if eax <> 0           mov ebx,[lbuffer]         mov byte [ebx+eax],0         .if SHOW_DETAILED_MSG             cinvoke printf,szRequest, [lbuffer]           .endif         cinvoke strtok, [lbuffer], szTockens         .if eax <> 0             ;handling the GET message             .if dword[eax] = "GET"                          ;url sring allocation                 ;getting the URL from GET message                 cinvoke malloc, MAX_URL_SIZE                 mov    [lurl],eax                 cinvoke strcpy, [lurl],szRoot                 cinvoke strtok, NULL, szTockens                 cinvoke strcat,[lurl],eax  

Page 36: Codigo Latino 9

                mov     ebx,eax                     cinvoke strlen, eax                 mov edx,eax                 dec edx                 .repeat                     dec eax                     cmp byte[ebx+eax],"/"                     .if ZERO?                         mov byte[ebx+eax],"\"                     .endif                                    .until eax = 0                 .if byte[ebx+edx] = "\"                     cinvoke strcat,[lurl],szIndex                 .endif                 cinvoke printf, szFile, [lurl]                 ;opening the file to send to browser                 invoke  CreateFile,[lurl],GENERIC_READ,FILE_SHARE_READ,                        0,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,0                 ;file exists, sending,,,,                 .if eax <> INVALID_HANDLE_VALUE                     mov [lfile],eax                                invoke  GetFileSize, [lfile],NULL                     invoke  TransmitFile, [lpeer],[lfile],eax,NULL,NULL,                            transmiteBuffer,NULL                     .if eax                         cinvoke printf, szStatus, szFileSended                     .endif                     invoke  CloseHandle, [lfile]                 .else                     cinvoke printf, szStatus, szFileNotExists                                        invoke  send, [lpeer], h404, h404.size, 0                               .endif                 cinvoke free, [lurl]             .endif         .endif     .endif     .exit:     cinvoke free, [lbuffer]     invoke  CloseHandle, [lpeer]     invoke  ExitThread     ret endp  ;convert DWORD ip  to ip sring for displaying later proc ipToString, ip, string local buffer: DWORD     mov ebx, [ip]     mov esi,4     mov eax,[string]     mov byte [eax],0     .repeat         xor     eax,eax         mov     al,bl         cinvoke sprintf,[buffer],szInt,eax 

Page 37: Codigo Latino 9

        cinvoke strcat,[string],[buffer]         cinvoke strcat,[string],szDot         shr ebx,8         dec esi     .until esi=0     cinvoke strlen, [string]     mov ebx, [string]     mov byte[ebx+eax­1],0     mov byte[buffer],0     ret endp 

section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\         user32,'USER32.DLL',\         msvcrt,'msvcrt.dll',\         wsock32, 'WSOCK32.DLL' include '%fasminc%\apia\kernel32.inc' include '%fasminc%\apia\user32.inc' include '%fasminc%\apia\msvcrt.inc' include '%fasminc%\apia\wsock32.inc' 

Variables importantes:     wsa WSADATA ; nuestro socket     port dd 80   ; el puerto que usamos para la escucha     ;nuestra cabecera h404     h404 db "HTTP/1.1 404 Not Found",13,10,"Server: EnkoHttpServer 1.0.0.0 ",            13,10,13,10,"<HTML><BODY>404 Not Found</BODY></HTML>",13,10     size = $ ­ h404     ;nuestra cabecera h200     h200 db "HTTP/1.1 200 OK",13,10,"Server: EnkoHttpServer 1.0.0.0 ",13,10,            "Allow: GET",13,10,13,10     .size = $ ­ h200     ;cual es la raiz de nuestro servidor     szRoot db "c:\httpServer",0     ;version del socket     wSocketVersion dd 0x0101     ;el buffer que se usa para transmitir el archivo, consta de la cabecera h200, del tamaña de la cabecera h200 y los demas parametros no se usan.     transmiteBuffer dd h200,h200.size,NULL,NULL 

Explicacion del código: Iniciamos el socket     ;inicializamos la conexiones     invoke  WSAStartup, [wSocketVersion], wsa     ;creamos un socket     invoke  socket,AF_INET,SOCK_STREAM,NULL     mov     [sock],eax        mov     [sock_addr.sin_family], AF_INET     ;pasamos el DWORD del puerto al formato para la escucha     invoke  htons,[port]     mov     [sock_addr.sin_port],ax        mov     [sock_addr.sin_addr],NULL 

Page 38: Codigo Latino 9

    ;abrimos el puerto con el socket, si hay un error lo mostramos     invoke  bind, [sock], sock_addr,sizeof.sockaddr_in     .if eax <> 0         invoke  WSAGetLastError         cinvoke printf, szError, eax            .endif        ;esperamos una respuesta     invoke listen, [sock],MAX_QUEUE 

Si seguimos, es porque hay una solicitud pendiente, procedemos a analizarla creando un hilo independiente para cada solicitud.    ;socket listening    ;aceptamos la solicitud del cliente    invoke accept, [sock],peerAddr,sizePeerAddr    ;guardamos los datos del cliente    mov     [peer],eax    stdcall ipToString,[peerAddr.sin_addr],szIp    ;mostramos la ip del cliente    cinvoke printf, szClient,szIp   ;Creamos el hilo, y le pasamos como parametro los datos del cliente    invoke CreateThread, NULL,NULL, resolveConnection,[peer],NULL,NULL 

Hay un cliente con una solicitud pendiente, procedemos a leer esa solicitud. Para eso creamos un buffer, así podemos recibir la url solicitada     ;lparam es son los datos del cliente, lpeer es una variable local, no confundir con peer que es global, y solo se usa para pasarse como parametro para la función del hilo.     mov     eax, [lpParam]     mov     [lpeer],eax     cinvoke malloc, BUFFER_SIZE     mov     [lbuffer],eax     ; recibimos la solicitud     invoke  recv, [lpeer],[lbuffer],BUFFER_SIZE,0     ;si hay un mensaje continuamos analizando, si no, se cierra la conexion     .if eax <> 0         .if dword[eax] = "GET" 

Solo nos interesa el metodo GET explicado al principio de este artículo, existe otros dos que son POST y HEADER que no vamos a analizar. Ahora en lbuffer tenemos el mensaje del cliente, necesitamos sacar de ahí la dirección del arhivo que quiere el cliente. En "GET /path/file.html HTTP/1.0" la url sería path/file.htm, a eso tenemos que sumarle la dirección de nuestro servidor, es decir si es C:\httServer, habría que agregarle path/file.html quedando C:\httpServer\path\file.html. (también necesitamos invertir las barras /) Una vez que obtuvimos la dirreccion del archivo, proseguimos:CreateFile,[lurl],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,0   .if eax <> INVALID_HANDLE_VALUE       mov [lfile],eax                  invoke  GetFileSize, [lfile],NULL       invoke  TransmitFile, [lpeer],[lfile],eax,NULL,NULL,transmiteBuffer,NULL 

Page 39: Codigo Latino 9

      .if eax          cinvoke printf, szStatus, szFileSended       .endif           invoke  CloseHandle, [lfile]    .else       cinvoke printf, szStatus, szFileNotExists                          invoke  send, [lpeer], h404, h404.size, 0                  .endif 

Abrimos el archivo, si no existe, envíamos la cabecera h404. Si existe, obtenemos el tamaño del archivo, y lo envíamos pasando como parámetros el handle del archivo, su tamaño y el buffer con la cabecera h200.

Con esto, hemos implementado un servidor web bastante potente. Puede mostrar páginas htm/html completas incluyendo imágenes, sonidos y demas. Pues la tarea difícil la hace el cliente web, cuando nosotros introducimos por ejemplo http://www.código latino.com.ar, el cliente es el que se encarga de analizar el código html, y solicitar al servidor las imagenes y todo aquello que necesite. Para cada recurso que necesite el cliente, va envíar un mensaje GET al servidor; así, manejando el metodo GET tenemos hecho más de la mitad de un servidor básico completo. Claro pues faltaría php, asp, y mensajes HEADER y POST pero eso ya es otra historia.

Para una buena referencia a protocolo http, visiten: http://www.jmarshall.com/easy/http/

Espero que les haya servido de algo el artículo. Saludos y sigan programando mucho.

Page 40: Codigo Latino 9

Exportar DB a PlanoPor Juez

1. Parametro: pTabla, pBuf pTabla = Este parametro recibe el nombre de la tabla que se quiere exportar pBuf = Este parametro recibe la posición que obtuvo el archivo creado en memoria. Esta posición se obtiene con =Fcreate() ó = Fopen() Ejm: if file('nombre.txt') vBuf = Fopen('c:\nombre.txt') else vBuf = Fcreate('c:\nombre.txt')

endif if vBuf > 0 && se Abrio el archivo o se creó satisfactoriamente &&Invocamos el metodo o prg y le pasamos los parametros exportar("tabla",vBuf) else && no se pudo abrir o crear el archivo endif

2. Declaración de Variables: vLong, cdPad, v1 , v2 vLong = esta variable recibirá un valor entero que nos sirvirá para saber el tamaño del campo. cdPad = esta variable será de tipo cadena que nos servirá para crear la cadena que completa el tamaño de lo que está escrito en el campo, con el tamaño del campo. Explicación especifica en la función Padr(). v1 = esta variable recibirá un valor entero que nos dirá la cantidad de registros

que contiene la tabla a procesar. v2 = esta variable será un contador de registros procesados.

3.Funciones utilizadas: reccount(), afields(), type(), transform(), fsize(), padr(), fwrite(), fflush(), fclose(), chr(). Reccount() = Esta función nos ayuda a obtener el total de registros de la tabla. afields() = Esta función crea una matriz con los campos de la tabla y retorna la cantidad de campos que tiene la tabla. type() = Esta función retorna el tipo de campo. Ejm. type('campo1') &&suponiendo que es un campo entero retornará I, caracter = C

Page 41: Codigo Latino 9

numerico = N date = D

datetime = T logico = L etc....

Con esta función se debe especificar el nombre del campo con comillas, ya que existe también la función vartype() que es más rápida y no requiere comillas. Se utilizó type() debido a como crea la afields() la matriz de los nombres. transform() = Toma diferentes tipo de datos y los transforma a caracter. fsize() = Esta función es utiliza para obtener el tamaño de archivos y de campos en bytes. padr() = Esta función crea una cadena y la rellena, si es necesario, a la derecha con

la expresión colocada Ejm: Si un campo de tipo numerico su tamaño definido en la estructura es 10 y el registro insertado solo tiene 5, sucedera esto al insertar Caso 1:

campo1, Campo2 12345,Detalle del campo

12345678,detalle del campo2 Caso 2: Al usar padr() nos ayudará que quede así: Campo1 ,Campo2

12345 ,Detalle del campo 12345678 ,detalle del campo

Se podría decir que es una tabulación. Ejmp: cdPad = padr(transform(campo1),vLong," ") Con las comillas le decimos que rellene de espacios en blanco para completar el tamaño. Fwrite() = Esta función es utiliza para escribir en archivos o puertos. A esta función se le coloca el controlador del arhivo (punto 1,parámetros) y la cadena a escribir.

Ejmp. Fwrite(pBuf,cdPad) fflush() = Esta función es para vaciar la memoria utilizada por el archivo lo asegura en el disco. Esta función es para archivos de bajo nivel.Se le coloca el controlador del archivo. Ejm: Fflus(pBuf) fclose() = Esta función cierra el archivo de bajo nivel y libera el controlador de memoria. Ejm: fclose(pBuf) chr() = Esta función es utilizada con valores ansi que se dan entre 0 y 255. En este caso solo necesitamos el 10 y 13 para dar el enter y colocarnos en la sig.linea 4. También se utilizó el comodín &. Este comodín se utiliza para ejecutar una macro, que vendria siendo el contenido que posee una variable o un vector.

Page 42: Codigo Latino 9

Código*!**!**!**!**!**!**!**!**!**!**!**!**!* *!*   Realizado Por Ariel Barria   *!** *!*   Seudonimo: Juez      *!** *!*   Exportar a Txt      *!** *!*   Realizado 25/02/2007         *!** *!*   www.solocodigo.com      *!** *!**!**!**!**!**!**!**!**!**!**!**!**!* Parameters pTabla,pBuf Local vLong, vPad vLong = 0 cdPad  = "" Select &vf Go Top v1 = Reccount() v2 = 0 vCant = Afields(mCampos) Do While !Eof() 

For i = 1 To vCant If(Type(mCampos[i,1]) = "T") Then 

vLong = 22 Endif If(Type(mCampos[i,1]) = "D") Then 

vLong = 10 Endif If(Type(mCampos[i,1]) = "L") Then 

vLong = 3 Endif If (vLong = 0) Then 

vLong = Fsize(mCampos[i,1]) Endif If(Transform(&mCampos[i,1]) = "0") Then 

cdPad  = Padr(Transform(&mCampos[i,1]),vLong,"0") Else 

cdPad  = Padr(Transform(&mCampos[i,1]),vLong," ") Endif If(i = vCant) 

=Fwrite(pBuf,cdPad+" ;"+Chr(13)+Chr(10)) Else 

=Fwrite(pBuf,cdPad) Endif If i => 1 And i <> vCant 

=Fwrite(pBuf,",") Endif vLong = 0 

Endfor Wait Window Nowait 'Exportando Datos a Txt....' +Str(v2)+' de '+Str(v1) v2 = v2 + 1 Select &vf Skip 

Enddo =Fflush(pBuf) =Fclose(pBuf) Wait Window Nowait  'Terminado' 

Page 43: Codigo Latino 9

Juego de la ViboraPor rob1104

Para este juego necesitamos:3 Formularios (frmPrincipal, frmPedirNombre, frmPausa)Formulario frmPrincipal1 StatusBar, 1 Timer, 1 MenúElementos del Formulario   Begin VB.Menu mnuBar       Caption         =   "&Juego"       Begin VB.Menu mnuJuego          Caption         =   "Juego &Nuevo"       Begin VB.Menu mnuJuego          Caption         =   "&Pausa"       Begin VB.Menu mnuJuego          Caption         =   "&Puntuaciones Altas"       Begin VB.Menu mnuJuego          Caption         =   "&Salir"    Begin VB.Menu mnuBar       Caption         =   "&Velocidad"       Begin VB.Menu mnuVelocidad          Caption         =   "Nivel 1"       End       Begin VB.Menu mnuVelocidad          Caption         =   "Nivel 2"       Begin VB.Menu mnuVelocidad          Caption         =   "Nivel 3"       Begin VB.Menu mnuVelocidad          Caption         =   "Nivel 4"       Begin VB.Menu mnuVelocidad          Caption         =   "Nivel 5"

Código FormularioOption Explicit 'La siguiente linea es para ajustar la posicion de la Serpiente Private PuntosX(), PuntosY(), largoVibora As Integer 'La siguietne linea es para ajustar la pocision de los puntos (que se come la serpiente) Public PosX As Integer, PosY As Integer, Puntuacion As Integer, nombre As String 'La siguietne linea es para ajustar la puntuacion Dim ValorPunto As Integer, Dificultad As String 'Las siguientes 6 lineas son la direccion de la serpiente Dim Direccion As Byte Private Const IZQUIERDA As Byte = 1 Private Const ARRIBA As Byte = 2 Private Const DERECHA As Byte = 3 Private Const ABAJO As Byte = 4 

Page 44: Codigo Latino 9

'Esta funcion establece que el punto es puesto en el formulario aleatoriamente 'y asegura qeu no este pusto en la misma posicion de la vibora Public Function ChecarPosicionDelPunto() As Boolean     Dim i As Integer     For i = 1 To largoVibora         If PosX = PuntosX(i) And PosY = PuntosY(i) Then             ChecarPosicionDelPunto = True             Exit Function         End If     Next i     ChecarPosicionDelPunto = False End Function 

'Esta subrutina verifica la tabla de puntuaciones 'Para ver si se ha hecho un nuevo record Public Sub ChecarTablaDePuntuaciones(ByVal PuntuacionAlta As Integer)     Dim i As Integer, num As Integer     If PuntuacionAlta < CInt(frmAltasPuntuaciones.lblPuntuacion(9).Caption) Then         Exit Sub     End If     num = 0     For i = 9 To 0 Step ­1        If PuntuacionAlta < CInt(frmAltasPuntuaciones.lblPuntuacion(i).Caption) Then             num = i + 1             Exit For        End If     Next i     frmPedirNombre.txtNombre.Text = nombre     frmPedirNombre.txtNombre.SelStart = 0     frmPedirNombre.txtNombre.SelLength = Len(frmPedirNombre.txtNombre.Text)     frmPedirNombre.Show vbModal, Me     For i = 8 To num Step ­1   frmAltasPuntuaciones.lblPuntuacion(i   +   1).Caption   = frmAltasPuntuaciones.lblPuntuacion(i).Caption   frmAltasPuntuaciones.lblNombre(i   +   1).Caption   = frmAltasPuntuaciones.lblNombre(i).Caption     Next i     frmAltasPuntuaciones.lblNombre(num).Caption = nombre     frmAltasPuntuaciones.lblPuntuacion(num).Caption = PuntuacionAlta End Sub 

'Esta funcion verifica si la serpiente comio un punto Public Function ChecarPunto() As Boolean     Dim i As Integer     For i = 1 To largoVibora ­ 1         If PuntosX(largoVibora) = PosX _           And PuntosY(largoVibora) = PosY Then             ChecarPunto = True             Exit Function         End If     Next i     ChecarPunto = False End Function 

Page 45: Codigo Latino 9

'Esta funcion verifica que la serpiente se ha comido a si misma o 'si ha chocado contra las paredes Public Function ChecarSiPerdio() As Boolean     Dim i As Integer     For i = 1 To largoVibora         If PuntosX(i) > Me.ScaleWidth _           Or PuntosX(i) < 0 Then             ChecarSiPerdio = True             Exit Function         End If         If PuntosY(i) > Me.ScaleHeight _           Or PuntosY(i) < 0 Then             ChecarSiPerdio = True             Exit Function         End If     Next i     For i = 1 To largoVibora ­ 1         If PuntosX(largoVibora) = PuntosX(i) _           And PuntosY(largoVibora) = PuntosY(i) Then             ChecarSiPerdio = True             Exit Function         End If     Next i     ChecarSiPerdio = False End Function 

'Esta subrutina checa la velocidad de la serpiente al empezar el juego Private Sub ChecarVelocidad()     Dim i As Integer     For i = 1 To 5         If mnuVelocidad(i).Checked = True Then             Call mnuVelocidad_Click(i)             Exit Sub         End If     Next i End Sub 

'Subrutina quedibuja un nuevo punto cuando el anterior es comido Public Sub DibujarPunto()     Me.DrawWidth = 9     PosX = ((Int(Int(Me.ScaleWidth / 10) * Rnd)) * 10)     PosY = ((Int(Int(Me.ScaleHeight / 10) * Rnd)) * 10)     Do While ChecarPosicionDelPunto = True         PosX = ((Int(Int(Me.ScaleWidth / 10) * Rnd)) * 10)         PosY = ((Int(Int(Me.ScaleHeight / 10) * Rnd)) * 10)     Loop     Me.PSet (PosX, PosY), RGB(255, 0, 0) End Sub 

'Esta sub dibuja la vibora en la direcciona deseada Public Sub DibujarVibora(ByVal dir As Byte)     Me.DrawWidth = 12     Dim i As Integer     Me.Line (PuntosX(1), PuntosY(1))­(PuntosX(2), PuntosY(2)), Me.BackColor 

Page 46: Codigo Latino 9

    For i = 1 To largoVibora ­ 1         PuntosX(i) = PuntosX(i + 1)         PuntosY(i) = PuntosY(i + 1)     Next i     Select Case dir         Case IZQUIERDA             PuntosX(largoVibora) = (PuntosX(largoVibora ­ 1) ­ Dificultad)             PuntosY(largoVibora) = PuntosY(largoVibora ­ 1)         Case ARRIBA             PuntosX(largoVibora) = PuntosX(largoVibora ­ 1)             PuntosY(largoVibora) = (PuntosY(largoVibora ­ 1) ­ Dificultad)         Case DERECHA             PuntosX(largoVibora) = (PuntosX(largoVibora ­ 1) + Dificultad)             PuntosY(largoVibora) = PuntosY(largoVibora ­ 1)         Case ABAJO             PuntosX(largoVibora) = PuntosX(largoVibora ­ 1)             PuntosY(largoVibora) = (PuntosY(largoVibora ­ 1) + Dificultad)     End Select     For i = 1 To largoVibora ­ 1         Me.Line (PuntosX(i), PuntosY(i))­(PuntosX(i + 1), PuntosY(i + 1)), RGB(0, 255, 0)     Next i     If ChecarSiPerdio = True Then         Timer1.Enabled = False         Call ChecarTablaDePuntuaciones(Puntuacion)     End If     If ChecarPunto = True Then         Puntuacion = Puntuacion + ValorPunto         Call DibujarPunto         Call extenderVibora     End If End Sub 

'Inicializa la vibora para un nuevo juego Public Sub inicializarVibora()     Dim i As Integer     ReDim PuntosX(1 To 10)     ReDim PuntosY(1 To 10)     largoVibora = 10     For i = 1 To largoVibora         PuntosX(i) = 10         PuntosY(i) = (10 * i)     Next i     For i = 1 To 9         Me.Line (PuntosX(i), PuntosY(i))­(PuntosX(i + 1), PuntosY(i + 1)), RGB(0, 0, 0)     Next i End Sub 

'Esto extiende el tamano de la vibora cuando la vibora come un punto Public Sub extenderVibora()     Dim i As Integer     largoVibora = largoVibora + 1     ReDim Preserve PuntosX(1 To largoVibora) 

Page 47: Codigo Latino 9

    ReDim Preserve PuntosY(1 To largoVibora)     For i = largoVibora To 2 Step ­1         PuntosX(i) = PuntosX(i ­ 1)         PuntosY(i) = PuntosY(i ­ 1)     Next i End Sub 

'Subrutina que captura la tecla presionada Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)     If KeyCode = 37 And Direccion <> DERECHA Then         Direccion = IZQUIERDA     ElseIf KeyCode = 38 And Direccion <> ABAJO Then         Direccion = ARRIBA     ElseIf KeyCode = 39 And Direccion <> IZQUIERDA Then         Direccion = DERECHA     ElseIf KeyCode = 40 And Direccion <> ARRIBA Then         Direccion = ABAJO     End If End Sub 

'Comienza el programa Private Sub Form_Load()     Randomize     Call JuegoNuevo     cargarPuntuaciones End Sub 

'Mientras termina el programa, graba las puntuaciones Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)     GuardarPuntuacion End Sub 

Private Sub mnuAcercade_Click()     frmAcercaDe.Show vbModal, Me End Sub 

'Menu Juego Private Sub mnuJuego_Click(Index As Integer)     Select Case Index         Case 1  'Nuevo             JuegoNuevo             Timer1.Enabled = True         Case 2  'Pausa             Timer1.Enabled = False             frmPausa.Show vbModal, Me             Timer1.Enabled = True         Case 4    'Puntuaciones             frmAltasPuntuaciones.Show vbModal, Me         Case 6    'Salir             Unload Me             End     End Select End Sub 

Page 48: Codigo Latino 9

'Velocidades Private Sub mnuVelocidad_Click(Index As Integer)     Dim i As Integer     For i = 1 To 5         mnuVelocidad(i).Checked = False     Next i     mnuVelocidad(Index).Checked = True     Select Case Index         Case 1             Dificultad = 10             Timer1.Interval = 150             ValorPunto = 5         Case 2             Dificultad = 10             Timer1.Interval = 110             ValorPunto = 10         Case 3             Dificultad = 10             Timer1.Interval = 70             ValorPunto = 15         Case 4             Dificultad = 10             Timer1.Interval = 40             ValorPunto = 20         Case 5             Dificultad = 10             Timer1.Interval = 1             ValorPunto = 25     End Select End Sub 

'Carga las puntuaciones cuando el programa empieza Public Sub cargarPuntuaciones()     Dim i As Integer, strNombre As String, strPuntuacion As String     Load frmAltasPuntuaciones     Open App.Path & ".\Puntuaciones.apu" For Input As #1     For i = 0 To 9         Input #1, strNombre, strPuntuacion         frmAltasPuntuaciones.lblNombre(i).Caption = strNombre         frmAltasPuntuaciones.lblPuntuacion(i).Caption = strPuntuacion     Next i     Close #1 End Sub 

'SubRutina para empezar un juego nuevo Public Sub JuegoNuevo()     Me.Cls     Direccion = ABAJO     Call inicializarVibora     Call DibujarPunto     Puntuacion = 0     ChecarVelocidad End Sub 

Page 49: Codigo Latino 9

'Guardar la puntuacion alta Private Sub GuardarPuntuacion()     Dim i As Integer     Open App.Path & ".\Puntuaciones.apu" For Output As #1     For i = 0 To 9   Write  #1,   frmAltasPuntuaciones.lblNombre(i).Caption, frmAltasPuntuaciones.lblPuntuacion(i).Caption     Next i     Close #1     Unload frmAltasPuntuaciones End Sub 

'El timer de Visual Basic xD Private Sub Timer1_Timer()     Call DibujarVibora(Direccion)     barraDeEstado.SimpleText = "Puntuacion: " & Puntuacion End Sub 

Formulario frmPedirNombre1 Botón, 1 TextBox, 1 LabelElementos del Formulario   Begin VB.CommandButton cmdOK       Caption = "E"    Begin VB.TextBox txtNombre    Begin VB.Label lbl1       Caption = "Has conseguido una puntuacion alta. Por favor escribe tu nombre" 

Código FormularioPrivate Sub cmdOK_Click()     frmPrincipal.nombre = txtNombre.Text     Unload Me End Sub 

Private Sub txtNombre_KeyUp(KeyCode As Integer, Shift As Integer)     Select Case KeyCode         Case 83             txtNombre.SelLength = 1             txtNombre.SelText = "S"     End Select End Sub 

Formulario frmPausa1 Label   Begin VB.Label Label2       Caption         =   "Presiona f3 para continuar" 

Código FormularioPrivate Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)     If KeyCode = 114 Then Unload Me End Sub 

Page 50: Codigo Latino 9

Esta entrega de Código Latino ha sido posible gracias a la ayuda de foreros de

Esperamos sus comentarios, códigos y artículos para la próxima entrega, esta es una revista de todos y para todos.

Pueden escribirnos a [email protected]

Hasta una próxima entrega.Chao