Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Juan_Perez

#1
Aquí les paso un ejemplo de una función recursiva en C++ que busca un archivo en una carpeta y todas sus subcarpetas.

Hice dos versiones, una para Windows y otra para GNU/Linux.
La versión para Windows la compilé con el Visual C++ .NET 2003 y el Dev C++ 4.9.9.2 bajo Windows XP pro SP2, y la de GNU/Linux con el g++ 4.1.2 bajo Ubuntu 6.0.

Probé ambos programas y aparentemente si encuentra las carpetas en donde se encuentra el archivo a buscar. Si lo prueban y encuentran errores les agradecería me los comentaran para corregirlos.

Versión Windows

#include <iostream>
#include <vector>
#include <string>

using namespace std;

#include <direct.h>
#include <io.h>

void FindFile (const string& archivo, const string& carpeta)
{
static struct _finddata_t c_file;
static long hFile;
static string filespec;

filespec = carpeta + "\\*.*";
if ((hFile = _findfirst (filespec.c_str(), &c_file )) == -1L )
return;

vector<string> carpetas;
do {
if ((c_file.attrib & _A_ARCH) != 0) { // no es un subdirectorio
if (c_file.name == archivo)
cout << '[' << carpeta << ']' << endl;
} else if ((c_file.attrib & _A_ARCH) == 0 && strcmp (c_file.name, ".") && strcmp (c_file.name, ".."))
carpetas.push_back (c_file.name);
} while (_findnext( hFile, &c_file ) == 0);
_findclose( hFile );

for (int i = 0; i < carpetas.size (); ++i)
FindFile (archivo, carpeta + "\\" + carpetas[i]);
}

int main(int argc, char* argv[])
{
   FindFile ("TimerSessionClient.java", "C:\\temp");
   return 0;
}

Versión GNU/Linux

#include <iostream>
#include <vector>
#include <string>

#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>

using namespace std;

void FindFile (const string& archivo, const string& carpeta)
{
static DIR *dir;
static struct dirent *mi_dirent;

if( (dir = opendir (carpeta.c_str())) == NULL )
return;

vector<string> carpetas;
while ((mi_dirent = readdir (dir)) != NULL) {
if (string (mi_dirent->d_name) == "." || string (mi_dirent->d_name) == "..")
continue;
string cadina = carpeta + '/' + mi_dirent->d_name;
struct stat structura;
if (stat (cadina.c_str(), &structura) < 0)
;//cout << "error en stat" << endl;
else if (S_ISDIR (structura.st_mode))
carpetas.push_back (mi_dirent->d_name);
else if (archivo == mi_dirent->d_name)
cout << '[' << cadina << ']' << endl;
}
closedir (dir);

for (int i = 0; i < carpetas.size(); ++i)
FindFile (archivo, carpeta + '/' + carpetas[i]);
}

int main ( int argc, char *argv[] )
{
FindFile ("sony-sleep", "/etc");
return 0;
}
#2
No es necesario que utilices un archivo auxiliar y después renombrarlo tal como lo haces en el código que pusistes, así puedes poner directamente

archivo1=fopen(nombre_archivo,"w");

sólo que hacerlo de esta manera conlleva algo de riesgo, ya que podrías darle accidentalmente el nombre de algún archivo que ya exista en el disco y borrarlo. Para evitar esto tendrías que verificarlo, poniendo antes la línea

archivo1=fopen(nombre_archivo,"r");

y comparar archivo1 con NULL. Si es distinto quiere decir que el archivo ya existe.

Por otra parte, si de verdad quieres renombrar un archivo, la función rename está disponible en Turbo C y está declarada en <stdio.h> así

int rename (const char *oldname, const char *newname);

en caso de que el archivo se renombre la función regresa el valor de zero y si no pudo renombrarlo regresa el valor de -1, y  modifica la variable global errno indicando el tipo de error ocurrido.
#3
Programación C/C++ / Re: funcion gotoxy ( x , x )
17 Diciembre 2005, 05:51 AM
ANELKAOS, me parece que estás confundiendo la instrucción goto del lenguaje C/C++, la cual interrumpe el flujo secuencial del programa saltándose a un lado que tu le especificas, con la función gotoxy (x, y), la cual mueve el cursor a una línea y columna específica, cuando programas en modo consola.
#4
Programación C/C++ / Re: funcion gotoxy ( x , x )
17 Diciembre 2005, 02:47 AM
La función gotoxy (int columna, int fila) es una función declarada en el encabezado <conio.h>, la cual viene en los compiladores de la línea de Turbo C (y también Borland C++) de la compañía Borland. Si usas otro compilador debes de buscar una función equivalente. En el compilador Dev C++ hay una emulación de las funciones declaradas en <conio.h>, pero antes tienes que bajarte esta librería y compilarla para poder usarla. Windows ofrece un conjunto de funciones para manejar la consola, entre las cuales está una equivalente a gotoxy, pero para poder usar estas funciones tienes que verificar si tu compilador puede usarlas. Esto lo puedes ver buscando el archivo de encabezado windows.h en el directorio include de tu compilador. La función es SetConsoleCursorPosition (HANDLE hConsoleOutput, COORD coord), pero su uso no es inmediato como la función gotoxy. Te muestro un ejemplo sencillo que mueve el cursor a la posición (10, 10) (aquí tienes que tomar en cuenta de que con gotoxy el origen es (1,1), mientras que con la otra función comienza en (0, 0))

#include <windows.h>
main ()
{
   HANDLE hConsoleOutput;
   COORD coord;
   hConsoleOutput = GetStdHandle (STD_OUTPUT_HANDLE);
   coord.X = 10; coord.Y = 10;
   SetConsoleCursorPosition (hConsoleOutput, coord);
}
.
   Si programas bajo GNU/Linux puedes usar la función move(int fila, int columna), que viene en la librería NCURSES la cual funciona en casi todas las distribuciones.
#5
Discúlpame, me faltó contestarte la segunda pregunta. Para pasar una cadena a mayúsculas o minúsculas tienes que usar la función toupper o la función tolower respectivamente a cada uno de los elementos del arreglo. Estas funciones vienen declaradas en el encabezado <ctype.h>. Para las mayúsculas lo podrías hacer así

int i;
for (i = 0; texto[i] != '\0'; i++)
   texto[i] = toupper (texto[i]);

y para las minúsculas igualmente pero usando la otra función.
#6
Cuando declaras una variable de esta manera

char texto[20];

estás declarando un arreglo de 20 caracteres y no le puedes asignar un valor directamente con el signo =. Si quieres asignarle la cadena "gaston" a este arreglo lo puedes hacer de varias maneras. Una es usando el signo = al momento de declarar el arreglo, de esta manera

char texto[20] = "gaston";

el compilador es quien se encarga de que el arreglo texto se inicialice con la cadena "gaston". Otra manera es usando la función strcpy declarada en el encabezado <string.h>, el cual copia una cadena en otra. así

strcpy (texto, "gaston");

Otra manera es usando la función sprintf declarada en el encabezado <stdio.h>, que hace lo mismo que la función printf, pero en vez de formatear la salida a la pantalla, la manda a una cadena. Lo harías de esta forma

sprintf (texto, "%s", "gaston");

Otra forma es asignarle directamente cada letra que compone la cadena "gaston" al arreglo texto así

texto[0] = 'g';
texto[1] = 'a';
texto[2] = 's';
texto[3] = 't';
texto[4] = 'o';
texto[5] = 'n';
texto[6] = '\0';

el último caracter es el caracter nulo, y es necesario ponérselo al final ya que las cadenas en C no tienen indicación del tamaño de cada arreglo como lo hacen otros lenguajes.
#7
Agradezco las gracias, pero más que deberme una, diría que nos la debemos todos en este y otros foros, ya que, al igual que tú, yo también he puesto mis dudas y no ha faltado quien me ha echado la mano, si no con la solución, al menos con una opinión o una guía de como solucionarlas, por lo que considero que lo menos que podemos hacer es a ayudarnos unos a otros, dentro de lo que cabe y según nuestro limitados conocimientos. Hasta pronto y suerte. :)
#8
Gracias por sus felicitaciones pero el mérito es del autor del libro Herbert Schildt, que fue el que escribió el código del programa, yo solamente lo modifiqué un poco. ABSO5777 tiene razón cuando dice que me faltaron esas cabeceras, lo que pasa es que el compilador de Turbo C v2.01 en donde compilé el programa no se queja cuando uno usa funciones como strcpy o int86 y otras que necesitan los encabezados mencionados y compila sin errores y genera el ejecutable del programa. Sowher, con respecto al código que maneja el ratón aquí te lo paso, sólo que me estoy fijando que éste hace uso de las funciones de consola las cuales vienen en la librería que proporciona el compilador de Microsoft Visual C++ y no sé qué tanto te podrían servir si estás programando en Turbo C++. Este programa viene en el libro Schildt's Windows 95 Programming in C and C++ del mismo autor Herbert Schildt, y fue impreso en el año 1995 por la editorial Osborne McGraw-Hill (ahora si está tal como viene en el libro, no lo modifiqué excepto por los comentarios y letreros que venían en inglés). Lo compilé sin problemas con el Visual C++ v6. De hecho, con las funciones que proporciona la consola no es necesario el truco de direccionar directamente a la memoria de video ni de usar interrupciones (como en int86), pues aquí hay funciones para escribir cadenas con su color y atributos y lo hace igual de rápido como en las funciones que se usaron en el código anterior que te pasé.

/* Manejando el ratón desde la consola */
/*
#include <windows.h>
#include <string.h>
#include <stdio.h>

main ()
{
HANDLE hStdin, hStdout;
char str[80] = "Presione una tecla para terminar.";
DWORD result;
COORD coord;
int x = 0, y = 0;
INPUT_RECORD inBuf;

/* Libera la vieja consola y comienza con una nueva * /
FreeConsole ();
AllocConsole ();

/* Le pone a la ventana de consola un título * /
SetConsoleTitle ("Demostración de ratón con la consola");

/* Obtiene los manejadores estándar * /
hStdin  = GetStdHandle (STD_INPUT_HANDLE);
hStdout = GetStdHandle (STD_OUTPUT_HANDLE);

WriteConsole (hStdout, str, strlen (str), &result, NULL);

/* muestra los eventos del ratón hasta que se presiona una tecla * /
do {
ReadConsoleInput (hStdin, &inBuf, 1, &result);
/* Reporta si ocurre un evento del ratón * /
if (inBuf.EventType == MOUSE_EVENT) {
sprintf (str, "Estado del botón: %lu, X, Y: %3lu, %3lu\n",
inBuf.Event.MouseEvent.dwButtonState,
inBuf.Event.MouseEvent.dwMousePosition.X,
inBuf.Event.MouseEvent.dwMousePosition.Y);
coord.X = 0;
coord.Y = 1;
SetConsoleCursorPosition (hStdout, coord);
WriteConsole (hStdout, str, strlen (str), &result, NULL);

/* Reporta si se dio un doble click * /
if (inBuf.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) {
sprintf (str, "Doble click\a");
coord.X = inBuf.Event.MouseEvent.dwMousePosition.X;
coord.Y = inBuf.Event.MouseEvent.dwMousePosition.Y;
SetConsoleCursorPosition (hStdout, coord);
WriteConsole (hStdout, str, strlen (str), &result, NULL);
Sleep (600); /* espera * /
SetConsoleCursorPosition (hStdout, coord);
strcpy (str, "               "); /* borra mensaje * /
WriteConsole (hStdout, str, strlen (str), &result, NULL);
}
}
} while (inBuf.EventType != KEY_EVENT);

return 0;
}


Si estás interesado te puedo pasar las funciones de consola necesarias para que modifiques el código de menu.
#9
Si quieres lograr el mismo efecto que los menus de Turbo C++ de borland necesitas manejar punteros directos a la memoria de video. En los antiguas máquinas, antes de Windows 95, podías acceder directamente a la memoria de video. En las de ahora, con Windows 98, ME, 2000 y XP no lo puedes hacer, pero estos SO's hacen una simulación de DOS, el antiguo sistema operativo que usaban esas máquinas; de modo que cuando corres en modo consola un programa que hace uso directamente de la memoria de video, éste corre transparentemente sin que te des cuenta de la simulación, por lo que para ti es como si la estuvieras direccionando realmente. Te paso el código de un programa de demostración de menus que saqué del libro C: Guía para usuarios expertos del autor Herbert Schildt y editorial McGraw Hill/Interamericana de España del año 1989 El código lo modifiqué ligeramente para ponerle colores y sombras y para usar la función cls (), ya que en el código original el autor usaba una interrupción de DOS (otra cosa que no puedes usar pero que simula Windows), pero al correr el programa en modo consola con Windows XP, la función nada hacía. El código me compiló sin problemas con el Turbo C v2.01, en el modelo Large. El programa no maneja el ratón, pero es fácil manejarlo en modo consola, con las funciones que para el manejo de éste proporciona Windows. Si te interesa por ahí tengo un pequeño programa de demostración del uso del ratón.

/*
   Programa ejemplo que utiliza las rutinas de un menu encadenado
   en el modo texto
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <dos.h>

#define BORDE        1
#define ESC         27
#define MAX_MENU    10
#define VID_INV   0x70
#define INT_VID   0x0F
#define NORM_VID     7
#define COLOR_LETRA        0x09
#define COLOR_PRIMLETRA    0x04

void pd_driver (void);
void inicializaVideo (void);
int menu_encadenado (int num);
int crea_menu (int num, char *menu[], char *teclas, int contador,
                                    int x, int y, int borde, int colorfondo);
void visualiza_menu (int num);
void pon_sombra (int num);
void dibuja_borde (int num);
int obtiene_resp (int num);
void escribe_cadena (int x, int y, char *p, int atrib);
void escribe_char (int x, int y, char ch, int atrib);
void guarda_video (int num);
void restaura_video (int num);
void cls (void);
void vete_xy (int x, int y);
int modo_video (void);
int esta_en (char *s, char c);

char far *mem_vid;

struct estructura_menu {
   int comienzax, finx, comienzay, finy;
   unsigned char *p;
   char **menu;
   char *teclas;
   int borde, contador;
   int activo, colorfondo;
} estructura[MAX_MENU];

char *fruta[] = {
   "Manzana... ",
   "Naranja    ",
   "Albaricoque",
   "Fresa...   ",
   "Pera       ",
   "Uva        "
};

char *color[] = {
   "Roja... ",
   "Amarilla",
   "Naranja ",
   "Verde   "
};

char *tipo_manzana[] = {
   "Rojo delicias",
   "Gallega      ",
   "Asturiana    ",
   "Jonatan      "
};

char *tipo_fresa[] = {
   "Salvaje   ",
   "Huelva    ",
   "Freson    ",
   "Rojo fuego"
};

void main (void)
{

   int i;

   inicializaVideo ();
   cls ();
   for (i = 0; i < 80; i++) {
      escribe_char (1, i, ' ', NORM_VID);
      escribe_char (24, i, ' ', NORM_VID);
   }
   escribe_cadena (1, 1, "Seleccione su fruta:", COLOR_LETRA);

   /* crea primero las estructuras de los menus */
   crea_menu (0, fruta, "mnafpu", 6, 5, 20, BORDE, 0x10);
   crea_menu (1, color, "ranv", 4, 9, 28, BORDE, 0x70);
   crea_menu (2, tipo_manzana, "rjwr", 4, 12, 32, BORDE, 0x50);
   crea_menu (3, tipo_fresa, "ahfr", 4, 9, 10, BORDE, 0x80);

   pd_driver (); /* activa el sistema de menus */

}

void pd_driver (void)
{
   int eleccion1, eleccion2, seleccion;

   /* se activa si se necesita */
   while ((eleccion1 = menu_encadenado (0)) != -1) {
      switch (eleccion1) {
         case 0: /* quiere una manzana */
            eleccion2 = menu_encadenado (1);
            if (eleccion2 != -1)
               if (eleccion2 != 0) {
                  char str[80] = "                                         ";
                  escribe_cadena (1, 22, str, NORM_VID);
                  strcpy (str, estructura[0].menu[0]);
                  sprintf (str + strlen (str) - 4, " %s", estructura[1].menu[eleccion2]);
                  escribe_cadena (1, 22, str, NORM_VID);
               } else {
                  seleccion = menu_encadenado (2); /* manzana roja */
                  if (seleccion != -1) {
                     char str[80] = "                                      ";
                     escribe_cadena (1, 22, str, NORM_VID);
                     strcpy (str, estructura[0].menu[0]);
                     sprintf (str + strlen (str) - 4, " %s", estructura[1].menu[0]);
                     sprintf (str + strlen (str) - 4, " %s", estructura[2].menu[seleccion]);
                     escribe_cadena (1, 22, str, NORM_VID);
                  }
                  restaura_video (2);
               }
            restaura_video (1);
            break;
         case 3: /* quiere una fresa */
            seleccion = menu_encadenado (3);
            if (seleccion != -1) {
                  char str[80] = "                                         ";
                  escribe_cadena (1, 22, str, NORM_VID);
                  strcpy (str, estructura[0].menu[3]);
                  sprintf (str + strlen (str) - 6, " %s", estructura[3].menu[seleccion]);
                  escribe_cadena (1, 22, str, NORM_VID);
            }
            restaura_video (3);
            break;
         default:
            escribe_cadena (1, 22, "                             ", NORM_VID);
            escribe_cadena (1, 22, estructura[0].menu[eleccion1], NORM_VID);
            break;
      }
   }
   restaura_video (0);
}

/* inicializa la variable que apunta a la memoria de video */
void inicializaVideo (void)
{
   int modov;

   modov = modo_video ();
   if (modov != 2 && modov != 3 && modov && 7) {
      printf ("Video en modo texto de 80 columnas");
      exit (1);
   }

   /* inicializa la dirección de la memoria RAM de video */
   if (modov == 7) mem_vid = (char far *)0xB0000000;
   else mem_vid = (char far *)0xB8000000;
}

/* visualiza un menu encadenado y devuelve la selección */
/* num   - número del menu */
int menu_encadenado (int num)
{
   int eleccion;

   /* obtiene la ventana activa */
   if (!estructura[num].activo) { /* no está en uso */
      guarda_video (num); /* guarda la pantalla actual */
      estructura[num].activo = 1; /* activa el flag */
   }

   if (estructura[num].borde) dibuja_borde (num);

   visualiza_menu (num); /* visualiza el menu menu */
   pon_sombra (num); /* pone una sombra a la derecha y abajo */
   return obtiene_resp (num); /* devuelve la respuesta */
}

/*
   Construye la estructura de un menu encadenado.
   un 1 se regresa si puede ser encadenada la estructura del menu
   de lo contrario se devuelve un 0
   int menu           - número del menu
   char *menu[]       - texto del menu
   char *teclas       - teclas clave
   int contador       - número de ítems del menu
   int x, y           - coordenadas X, Y de la esquina superior izquiera
   int borde          - sin borde si es 0
*/
int crea_menu (int num, char *menu[], char *teclas, int contador,
                                     int x, int y, int borde, int colorfondo)
{
   register int i, len;
   int finx, finy, eleccion, modov;
   unsigned char *p;

   if (num > MAX_MENU) {
      printf ("Demasiados menus\n");
      return 0;
   }

   if (x > 24 || x < 0 || y > 79 || y < 0) {
      printf ("Error de rango\n");
      return 0;
   }

   /* calcula el tamaño */
   len = 0;
   for (i = 0; i < contador; i++)
      if (strlen (menu[i]) > len) len = strlen (menu[i]);
   finy = len + 3 + y;
   finx = contador + 1 + x;
   if ((finx + 1 > 24) || (finy + 1 > 179)) {
      printf ("No cabe el menu\n");
      return 0;
   }

   /* asignar suficiente memoria para almacenarlo */
   p = (unsigned char *)malloc (2 * (finx - x + 2) * (finy - y + 2));
   if (!p) exit (1); /* ponga aqu¡ su propio manejador de errores */

   /* construye la estructura */
   estructura[num].comienzax = x; estructura[num].finx = finx;
   estructura[num].comienzay = y; estructura[num].finy = finy;
   estructura[num].p = p;
   estructura[num].menu = (char **)menu;
   estructura[num].borde = borde;
   estructura[num].teclas = teclas;
   estructura[num].contador = contador;
   estructura[num].activo = 0;
   estructura[num].colorfondo = colorfondo;
   return 1;
}

/* visualiza el menu en su posición */
void visualiza_menu (int num)
{
   register int i, x;
   char **m;

   x = estructura[num].comienzax + 1;
   m = estructura[num].menu;

   for (i = 0; i < estructura[num].contador; i++, x++) {
      escribe_cadena (x, estructura[num].comienzay + 2, m[i],
                                   COLOR_LETRA | estructura[num].colorfondo);
      escribe_char (x, estructura[num].comienzay + 2, m[i][0],
                               COLOR_PRIMLETRA | estructura[num].colorfondo);
   }
}

void pon_sombra (int num)
{
   register int i;
   char far *v;

   v = mem_vid + (estructura[num].comienzax * 160) + (estructura[num].finy + 1) * 2 + 1;
   for (i = estructura[num].comienzax+1; i <= estructura[num].finx+1; i++) {
      v += 160;
      *v = NORM_VID;
   }
   v = mem_vid + ((estructura[num].finx + 1) * 160) + estructura[num].comienzay*2 + 1;
   for (i = estructura[num].comienzay+1; i <= estructura[num].finy+1; i++) {
      v += 2;
      *v = NORM_VID;
   }
}

void dibuja_borde (int num)
{
   register int i;
   char far *v, far *t;

   v = mem_vid;
   t = v;
   for (i = estructura[num].comienzax + 1; i < estructura[num].finx; i++) {
      v += (i * 160) + estructura[num].comienzay * 2;
      *v++ = 179;
      *v = estructura[num].colorfondo;
      v = t;
      v += (i * 160) + estructura[num].finy * 2;
      *v++ = 179;
      *v = estructura[num].colorfondo;
      v = t;
   }
   for (i = estructura[num].comienzay + 1; i < estructura[num].finy; i++) {
      v += estructura[num].comienzax * 160 + i*2;
      *v++ = 196;
      *v = estructura[num].colorfondo;
      v = t;
      v += (estructura[num].finx * 160) + i*2;
      *v++ = 196;
      *v = estructura[num].colorfondo;
      v = t;
   }
   escribe_char (estructura[num].comienzax, estructura[num].comienzay, 218, estructura[num].colorfondo);
   escribe_char (estructura[num].comienzax, estructura[num].finy, 191, estructura[num].colorfondo);
   escribe_char (estructura[num].finx, estructura[num].comienzay, 192, estructura[num].colorfondo);
   escribe_char (estructura[num].finx, estructura[num].finy, 217, estructura[num].colorfondo);
}

/* obtiene la selección del usuario */
int obtiene_resp (int num)
{
   union inkey {
      char ch[2];
      int i;
   } c;
   int flecha = 0, oldflecha = 0, tecla_elegida;
   int x, y;

   x = estructura[num].comienzax + 1;
   y = estructura[num].comienzay + 2;

   /* sobre-ilumina la primera selección */
   vete_xy (x, y);
   escribe_cadena (x, y, estructura[num].menu[0], INT_VID);
   escribe_char (x, y-1, ' ', INT_VID);
   escribe_char (x, estructura[num].finy-1, ' ', INT_VID);

   for (;;) {
      while (!bioskey (1)); /* espera hasta pulse tecla */
      c.i = bioskey (0);    /* lee la tecla */

      if (c.ch[0]) { /* es una tecla normal */
         /* ve si es una tecla clave */
         tecla_elegida = esta_en (estructura[num].teclas, tolower (c.ch[0]));
         if (tecla_elegida) return tecla_elegida - 1;
         /* comprueba ENTER o un espacio */
         if (c.ch[0] == ' ')
            flecha++;
         else if (c.ch[0] == '\r' || c.ch[0] == ESC) {
            escribe_char (x + flecha, y-1, ' ', estructura[num].colorfondo);
            escribe_char (x + flecha, estructura[num].finy-1, ' ', estructura[num].colorfondo);
            return (c.ch[0] == '\r') ? flecha : -1;
         }
      } else { /* es una tecla especial */
         switch (c.ch[1]) {
            case 72: flecha--; /* flecha arriba */
               break;
            case 80: flecha++; /* flecha abajo */
               break;
         }
      }
      if (flecha == oldflecha)
         continue;
      /* inicializa el modo normal de video */
      escribe_cadena (x + oldflecha, y, estructura[num].menu[oldflecha], estructura[num].colorfondo | COLOR_LETRA);
      escribe_char (x + oldflecha, y, estructura[num].menu[oldflecha][0], estructura[num].colorfondo | COLOR_PRIMLETRA);
      escribe_char (x + oldflecha, y-1, ' ', estructura[num].colorfondo);
      escribe_char (x + oldflecha, estructura[num].finy-1, ' ', estructura[num].colorfondo);

      if (flecha == estructura[num].contador) flecha = 0;
      if (flecha < 0) flecha = estructura[num].contador - 1;
      oldflecha = flecha;

      /* sobre-ilumina la proxima selección */
      vete_xy (x + flecha, y);
      escribe_cadena (x + flecha, y, estructura[num].menu[flecha], INT_VID);
      escribe_char (x + flecha, y-1, ' ', INT_VID);
      escribe_char (x + flecha, estructura[num].finy-1, ' ', INT_VID);
   }
}

/* visualiza una cadena con atributo especificado */
void escribe_cadena (int x, int y, char *p, int atrib)
{
   register int i;
   char far *v;

   v = mem_vid;
   v += (x * 160) + y*2; /* calcula la direcci¢n */
   for (i = y; *p; i++) {
      *v++ = *p++; /* escribe el caracter */
      *v++ = atrib; /* escribe el atributo */
   }
}

/* Escribe caracter con atributo especificado */
void escribe_char (int x, int y, char ch, int atrib)
{
   register int i;
   char far *v;

   v = mem_vid;
   v += (x * 160) + y*2; /* calcula la dirección */
   *v++ = ch; /* escribe el caracter */
   *v   = atrib; /* escribe el atributo */
}

/* guarda una porción de la pantalla */
void guarda_video (int num)
{
   register int i, j;
   char far *v, far *t;
   char *ptr_buf;

   ptr_buf = estructura[num].p;
   v = mem_vid;
   for (i = estructura[num].comienzay; i <= estructura[num].finy+1; i++)
      for (j = estructura[num].comienzax; j <= estructura[num].finx+1; j++) {
         t = (v + (j * 160) + i*2);
         *ptr_buf++ = *t++;
         *ptr_buf++ = *t;
         if (i != estructura[num].finy+1 && j != estructura[num].finx+1) {
            *(t-1) = ' '; /* limpia la ventana */
            *t = estructura[num].colorfondo;
         }
      }
   estructura[num].activo = 0; /* desactiva */
}

/* restaura una porción de la pantalla */
void restaura_video (int num)
{
   register int i, j;
   char far *v, far *t;
   char *ptr_buf;

   ptr_buf = estructura[num].p;
   v = mem_vid;
   t = v;
   for (i = estructura[num].comienzay; i <= estructura[num].finy+1; i++)
      for (j = estructura[num].comienzax; j <= estructura[num].finx+1; j++) {
         v = t;
         v += (j * 160) + i*2; /* calcula la direcci¢n */
         *v++ = *ptr_buf++;    /* escribe el caracter */
         *v = *ptr_buf++;      /* escribe el atributo */
      }
   estructura[num].activo = 0; /* desactiva */
}

/* limpia la pantalla */
void cls (void)
{
   int i, j;

   for (i = 0; i < 25; i++)
      for (j = 0; j < 80; j++)
escribe_char (i, j, 0xB1, 0x0F);
}

/* enviar el cursor a x, y */
void vete_xy (int x, int y)
{
   union REGS r;

   r.h.ah = 2; /* función de direccionamiento del cursor */
   r.h.dl = y; /* coordenadas de la columna */
   r.h.dh = x; /* coordenadas de la fila */
   r.h.bh = 0; /* página de video */
   int86 (0x10, &r, &r);
}

/* devuelve el modo actual de video */
int modo_video (void)
{
   union REGS r;

   r.h.ah = 15; /* obtiene el modo de video */
   return int86 (0x10, &r, &r) & 255;
}

int esta_en (char *s, char c)
{
   register int i;

   for (i = 0; *s; i++)
      if (*s++ == c)
return i + 1;
   return 0;
}
#10
Les dejo una función que genera números aleatorios. Esta está codificada en Pascal pero se puede adaptar fácilmente a Visual Basic, sólo usa las operaciones aritméticas y los operadores binarios DIV y MOD, los cuales dan el cociente y el residuo de una división entera respectivamente. Esta función y el texto en cursiva abajo lo saqué del libro "Pascal Avanzado. Técnicas de Programación" de Paul Sand, de la editorial McGraw-Hill 1985. Libro excelente para el programador en general, no sólo el que programa en Pascal, ya que su énfasis es en las técnicas de programación antes que en un lenguaje específico como Pascal. En el desarrollan en cada capítulo programas útiles o interesantes (entrada interactiva, una calculadora de propósito general, el juego de tablero reversi, simulación y animación y en el último capítulo un auténtico proyecto: una hoja de cálculo).
Esta función viene en el apéndice del libro y el autor la puso para resolver problemas de transportabilidad con las versiones de Pascal que no soportaban números aleatoreos, función que el usa en el capítulo de simulación y animación.

function random: integer;
{ Devuelve un entero aleatorio en el rango 0..32767 }
var
   i, j, carry, t: integer;
begin { random }
   for i := 1 to 7 do begin
      carry := 0;
      for j := 1 to 4 do begin
         t := 2 * seed[j] + carry;
         carry := t div 256;
         seed[j] := t mod 256
      end;
      if (seed[1] div 128) <> (seed[4] div 128) then
         seed[1] := (seed[1] + 1) mod 256
   end;
   random := 256 * (seed[1] div 2) + seed[3]
end;

   Este array debe ser global para que guarde sus valores entre diferentes llamadas a random. El array debe ser inicializado antes de cualquier llamada a random; por ejemplo:
...
seed[1] := 90;
seed[2] := 178;
seed[3] := 246;
seed[4] := 147;
...
   Sin embargo, si asignamos los valores iniciales al array seed de esta forma, obtendremos siempre la misma secuencia aleatoria (lo cual es deseable en muchas circunstancias). Para evitar esto, Apple Pascal suministra el procedimiento randomize, el cual hace que se generen diferentes secuencias aleatorias. El mismo efecto puede obtenerse cambiando los elementos del array seed a otros valores antes de que se haga cualquier llamada a random; cómo puede hacerse esto se lo dejamos a usted. Por ejemplo, podría coger el intervalo de tiempo en ciclos de máquina entre la pulsación de dos teclas.
   Esta rutina fue extraída de Seminumerical Algortihms de D. Knuth (Adison-Wesley, 1981). Esta obra clásica contiene información sobre aritmética y generadores de números aleatoreos.