Codigo Latino 9
-
Upload
anon-534504 -
Category
Documents
-
view
1.782 -
download
0
description
Transcript of 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 .
● 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)
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 tlinetdline,
data_rand TYPE REF TO data, data_lines TYPE REF TO data. *&* * FIELDSYMBOLS * *&* FIELDSYMBOLS: <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 syucomm, ran_int TYPE qf00ran_int, flag TYPE c, counter TYPE c, gv_line TYPE string, button_count TYPE c, xtext TYPE tlinetdline, 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. ** * STARTOFSELECTION * ** STARTOFSELECTION. CALL SCREEN 0100. *&* *& Form call_editor * *&* FORM call_editor. IF text_editor IS INITIAL. CREATE OBJECT custom_container EXPORTING
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 sysubrc 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
*&* *& 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.
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,syucomm. ENDIF. ENDFORM. " validate_game *&* *& Module STATUS_0100 OUTPUT * *&* MODULE status_0100 OUTPUT. SET PFSTATUS 'MAIN'. SET TITLEBAR 'TITLE'. IF flag EQ space. PERFORM call_editor. ELSE. LOOP AT SCREEN. IF screenname EQ 'ONE' AND gv_flag_one EQ 'X'. screeninvisible = 1. MODIFY SCREEN. ENDIF. IF screenname EQ 'TWO' AND gv_flag_two EQ 'X'. screeninvisible = 1. MODIFY SCREEN. ENDIF. IF screenname EQ 'THREE' AND gv_flag_three EQ 'X'. screeninvisible = 1. MODIFY SCREEN. ENDIF. IF screenname EQ 'FOUR' AND gv_flag_four EQ 'X'. screeninvisible = 1. MODIFY SCREEN. ENDIF.
IF screenname EQ 'FIVE' AND gv_flag_five EQ 'X'. screeninvisible = 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 = syucomm. 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
Finalmente, tomé algunos pantallazos -;)
Espero que les guste -:) Saludos, Blag
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
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
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
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;
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.
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 ;)
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:iso88591 * 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'
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:iso88591 * 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:iso88591 * 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
#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
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).
[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
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.
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
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.
* * 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 021111307, USA. * * Any nonGPL 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); } }); }
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()
{ 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 (
dlgDate.getYear() + "/" + dlgDate.getMonth() + "/" + dlgDate.getDay() ); }
}
Mas informacion: http://www.toedter.com
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.
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]);
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.
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.
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.
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 ?
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
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
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+eax1],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
;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
.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.
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
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.
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'
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
'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
'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
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)
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
'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
'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
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