Hilo
Duda con winapi (ruben) 2018-10-21 12:56:59
Buenas,
Estoy aprendiendo a usar winapi con el curso de cconclase y es realmente bueno.
Se me a presentado un problema que no tengo claro como gestionarlo. Estoy acostumbrado a programar en consola y cuando quieres hacer un bucle que tarde su tiempo, simplemente hay que esperar a que termine.
El caso es que si activo un bucle con WM_COMAND, la aplicación se cuelga hasta que el bucle finalice.
Como tendría que hacer para ejecutar un bucle/funcion que tarde 10 minutos por ejemplo sin que deje de responder la aplicación? El ejemplo 4 del curso es perfecto para mostrar lo que yo he hecho (está marcado en rojo).
Para solucionarlo he pensado en activar un boleano con WM_COMAND y después ejecutar el bucle en otro sitio, e incluso segmentar el bucle para que valla funcionando poco a poco, pero creo esto simplemente camufla el problema. No se si hay una solución más obvia para esto.
Muchas gracias por vuestro tiempo.
Un saludo
#include <windows.h>
#include <stdio.h>
#include "main.h"
/* Declaración del procedimiento de ventana */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc2(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* Manipulador de ventana */
MSG mensaje; /* Mensajes recibidos por la aplicación */
WNDCLASSEX wincl; /* Estructura de datos para la clase de ventana */
/* Estructura de la ventana */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = "NUESTRA_CLASE";
wincl.lpfnWndProc = WindowProcedure; /* Esta función es invocada por Windows */
wincl.style = CS_DBLCLKS; /* Captura los doble-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Usar icono y puntero por defector */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = "Menu";
wincl.cbClsExtra = 0; /* Sin información adicional para la */
wincl.cbWndExtra = 0; /* clase o la ventana */
/* Usar el color de fondo por defecto para la ventana */
wincl.hbrBackground = GetSysColorBrush(COLOR_BACKGROUND);
/* Registrar la clase de ventana, si falla, salir del programa */
if(!RegisterClassEx(&wincl)) return 0;
/* La clase está registrada, crear la ventana */
hwnd = CreateWindowEx(
0, /* Posibilidades de variación */
"NUESTRA_CLASE", /* Nombre de la clase */
"Ejemplo 004", /* Texto del título */
WS_OVERLAPPEDWINDOW, /* Tipo por defecto */
CW_USEDEFAULT, /* Windows decide la posición */
CW_USEDEFAULT, /* donde se coloca la ventana */
544, /* Ancho */
375, /* Alto en pixels */
HWND_DESKTOP, /* La ventana es hija del escritorio */
NULL, /* Sin menú */
hThisInstance, /* Manipulador de instancia */
NULL /* No hay datos de creación de ventana */
);
/* Mostrar la ventana */
ShowWindow(hwnd, SW_SHOWDEFAULT);
/* Bucle de mensajes, se ejecuta hasta que haya error o GetMessage devuelva FALSE */
while(TRUE == GetMessage(&mensaje, NULL, 0, 0))
{
/* Traducir mensajes de teclas virtuales a mensajes de caracteres */
TranslateMessage(&mensaje);
/* Enviar mensaje al procedimiento de ventana */
DispatchMessage(&mensaje);
}
/* Salir con valor de retorno */
return mensaje.wParam;
}
/* Esta función es invocada por la función DispatchMessage() */
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance;
static int veces;
switch (msg) /* manipulador del mensaje */
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT)lParam)-> hInstance;
return 0;
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case CM_DIALOGO2:
//bucle
DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc2, veces);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */
break;
default: /* para los mensajes de los que no nos ocupamos */
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
BOOL CALLBACK DlgProc2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
char texto[25];
switch (msg) /* manipulador del mensaje */
{
case WM_INITDIALOG:
sprintf(texto, "Veces invocado: %d", (int)lParam);
SetWindowText(GetDlgItem(hDlg, TEXTO), texto);
return TRUE;
case WM_COMMAND:
EndDialog(hDlg, FALSE);
return TRUE;
}
return FALSE;
}
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
Re: Duda con winapi (Carlos Ernesto Obregon Suarez) 2018-10-21 14:52:56
Es normal que se cuelgue hasta que el bucle finalice si lo haces de esa
forma. Al ejecutarse el COMMAND y entrar en el bucle, mientras se esté
ejecutando no podrá avanzar al break del COMMAND.
Que es lo que necesitas hacer con bucle?
El dom., 21 de oct. de 2018 8:28 AM, Rubén Blanco Fernández <
darkmalka@hotmail.com> escribió:
> Buenas,
>
> Estoy aprendiendo a usar winapi con el curso de cconclase y es realmente
> bueno.
>
>
> Se me a presentado un problema que no tengo claro como gestionarlo. Estoy
> acostumbrado a programar en consola y cuando quieres hacer un bucle que
> tarde su tiempo, simplemente hay que esperar a que termine.
>
>
> El caso es que si activo un bucle con WM_COMAND, la aplicación se cuelga
> hasta que el bucle finalice.
>
>
> Como tendría que hacer para ejecutar un bucle/funcion que tarde 10 minutos
> por ejemplo sin que deje de responder la aplicación? El ejemplo 4 del
> curso es perfecto para mostrar lo que yo he hecho (está marcado en rojo).
>
>
> Para solucionarlo he pensado en activar un boleano con WM_COMAND y
> después ejecutar el bucle en otro sitio, e incluso segmentar el bucle para
> que valla funcionando poco a poco, pero creo esto simplemente camufla el
> problema. No se si hay una solución más obvia para esto.
>
>
> Muchas gracias por vuestro tiempo.
>
>
> Un saludo
>
>
>
>
> #include <windows.h>
> #include <stdio.h>
> #include "main.h"
>
> /* Declaración del procedimiento de ventana */
> LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
> BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
> BOOL CALLBACK DlgProc2(HWND, UINT, WPARAM, LPARAM);
>
> int WINAPI WinMain (HINSTANCE hThisInstance,
> HINSTANCE hPrevInstance,
> LPSTR lpszArgument,
> int nFunsterStil)
> {
> HWND hwnd; /* Manipulador de ventana */
> MSG mensaje; /* Mensajes recibidos por la aplicación */
> WNDCLASSEX wincl; /* Estructura de datos para la clase de
> ventana */
>
> /* Estructura de la ventana */
> wincl.hInstance = hThisInstance;
> wincl.lpszClassName = "NUESTRA_CLASE";
> wincl.lpfnWndProc = WindowProcedure; /* Esta función es invocada
> por Windows */
> wincl.style = CS_DBLCLKS; /* Captura los doble-clicks
> */
> wincl.cbSize = sizeof (WNDCLASSEX);
>
> /* Usar icono y puntero por defector */
> wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
> wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
> wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
> wincl.lpszMenuName = "Menu";
> wincl.cbClsExtra = 0; /* Sin información
> adicional para la */
> wincl.cbWndExtra = 0; /* clase o la ventana */
> /* Usar el color de fondo por defecto para la ventana */
> wincl.hbrBackground = GetSysColorBrush(COLOR_BACKGROUND);
>
> /* Registrar la clase de ventana, si falla, salir del programa */
> if(!RegisterClassEx(&wincl)) return 0;
>
> /* La clase está registrada, crear la ventana */
> hwnd = CreateWindowEx(
> 0, /* Posibilidades de variación */
> "NUESTRA_CLASE", /* Nombre de la clase */
> "Ejemplo 004", /* Texto del título */
> WS_OVERLAPPEDWINDOW, /* Tipo por defecto */
> CW_USEDEFAULT, /* Windows decide la posición */
> CW_USEDEFAULT, /* donde se coloca la ventana */
> 544, /* Ancho */
> 375, /* Alto en pixels */
> HWND_DESKTOP, /* La ventana es hija del escritorio */
> NULL, /* Sin menú */
> hThisInstance, /* Manipulador de instancia */
> NULL /* No hay datos de creación de ventana */
> );
>
> /* Mostrar la ventana */
> ShowWindow(hwnd, SW_SHOWDEFAULT);
>
> /* Bucle de mensajes, se ejecuta hasta que haya error o GetMessage
> devuelva FALSE */
> while(TRUE == GetMessage(&mensaje, NULL, 0, 0))
> {
> /* Traducir mensajes de teclas virtuales a mensajes de caracteres
> */
> TranslateMessage(&mensaje);
> /* Enviar mensaje al procedimiento de ventana */
> DispatchMessage(&mensaje);
> }
>
> /* Salir con valor de retorno */
> return mensaje.wParam;
> }
>
>
> /* Esta función es invocada por la función DispatchMessage() */
> LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam,
> LPARAM lParam)
> {
> static HINSTANCE hInstance;
> static int veces;
>
> switch (msg) /* manipulador del mensaje */
> {
> case WM_CREATE:
> hInstance = ((LPCREATESTRUCT)lParam)-> hInstance;
> return 0;
> break;
> case WM_COMMAND:
> switch(LOWORD(wParam)) {
>
> case CM_DIALOGO2:
> //bucle
> DialogBoxParam(hInstance, "DialogoPrueba", hwnd,
> DlgProc2, veces);
> break;
> }
> break;
> case WM_DESTROY:
> PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de
> mensajes */
> break;
> default: /* para los mensajes de los que no nos
> ocupamos */
> return DefWindowProc(hwnd, msg, wParam, lParam);
> }
> return 0;
> }
>
> BOOL CALLBACK DlgProc2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
> {
> char texto[25];
>
> switch (msg) /* manipulador del mensaje */
> {
> case WM_INITDIALOG:
> sprintf(texto, "Veces invocado: %d", (int)lParam);
> SetWindowText(GetDlgItem(hDlg, TEXTO), texto);
> return TRUE;
> case WM_COMMAND:
> EndDialog(hDlg, FALSE);
> return TRUE;
> }
> return FALSE;
> }
>
> _______________________________________________
> Lista de correo Cconclase Cconclase@listas.conclase.net
> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
Re: Duda con winapi (ruben) 2018-10-22 02:21:23
Buenas,
El bucle realmente lo puse como ejemplo para simplificar.
En este caso lo necesito para descargar registros de una API y en ciertos casos puede tardar horas dependiendo de la cantidad de registros.
Por eso mismo que dices pensé en simplemente poner un boleano en el WD_COMAND y meter todo en el main, pero el problema iba a ser el mismo ya que esté donde esté el "bucle", hasta acabarlo no se pasaría de ahí.
Lo que comenta Salvador de crear hilos es justo lo que necesitaba, poder realizar tareas diferentes simultáneamente.
Gracias por responder.
Un saludo
________________________________
De: Cconclase <cconclase-bounces@listas.conclase.net> en nombre de Programacion Matematica <progmath13@gmail.com>
Enviado: domingo, 21 de octubre de 2018 16:52
Para: Lista de correo sobre C y C++
Asunto: Re: [C con Clase] Duda con winapi
Es normal que se cuelgue hasta que el bucle finalice si lo haces de esa forma. Al ejecutarse el COMMAND y entrar en el bucle, mientras se esté ejecutando no podrá avanzar al break del COMMAND.
Que es lo que necesitas hacer con bucle?
El dom., 21 de oct. de 2018 8:28 AM, Rubén Blanco Fernández <darkmalka@hotmail.com<mailto:darkmalka@hotmail.com> > escribió:
Buenas,
Estoy aprendiendo a usar winapi con el curso de cconclase y es realmente bueno.
Se me a presentado un problema que no tengo claro como gestionarlo. Estoy acostumbrado a programar en consola y cuando quieres hacer un bucle que tarde su tiempo, simplemente hay que esperar a que termine.
El caso es que si activo un bucle con WM_COMAND, la aplicación se cuelga hasta que el bucle finalice.
Como tendría que hacer para ejecutar un bucle/funcion que tarde 10 minutos por ejemplo sin que deje de responder la aplicación? El ejemplo 4 del curso es perfecto para mostrar lo que yo he hecho (está marcado en rojo).
Para solucionarlo he pensado en activar un boleano con WM_COMAND y después ejecutar el bucle en otro sitio, e incluso segmentar el bucle para que valla funcionando poco a poco, pero creo esto simplemente camufla el problema. No se si hay una solución más obvia para esto.
Muchas gracias por vuestro tiempo.
Un saludo
#include <windows.h>
#include <stdio.h>
#include "main.h"
/* Declaración del procedimiento de ventana */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc2(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* Manipulador de ventana */
MSG mensaje; /* Mensajes recibidos por la aplicación */
WNDCLASSEX wincl; /* Estructura de datos para la clase de ventana */
/* Estructura de la ventana */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = "NUESTRA_CLASE";
wincl.lpfnWndProc = WindowProcedure; /* Esta función es invocada por Windows */
wincl.style = CS_DBLCLKS; /* Captura los doble-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Usar icono y puntero por defector */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = "Menu";
wincl.cbClsExtra = 0; /* Sin información adicional para la */
wincl.cbWndExtra = 0; /* clase o la ventana */
/* Usar el color de fondo por defecto para la ventana */
wincl.hbrBackground = GetSysColorBrush(COLOR_BACKGROUND);
/* Registrar la clase de ventana, si falla, salir del programa */
if(!RegisterClassEx(&wincl)) return 0;
/* La clase está registrada, crear la ventana */
hwnd = CreateWindowEx(
0, /* Posibilidades de variación */
"NUESTRA_CLASE", /* Nombre de la clase */
"Ejemplo 004", /* Texto del título */
WS_OVERLAPPEDWINDOW, /* Tipo por defecto */
CW_USEDEFAULT, /* Windows decide la posición */
CW_USEDEFAULT, /* donde se coloca la ventana */
544, /* Ancho */
375, /* Alto en pixels */
HWND_DESKTOP, /* La ventana es hija del escritorio */
NULL, /* Sin menú */
hThisInstance, /* Manipulador de instancia */
NULL /* No hay datos de creación de ventana */
);
/* Mostrar la ventana */
ShowWindow(hwnd, SW_SHOWDEFAULT);
/* Bucle de mensajes, se ejecuta hasta que haya error o GetMessage devuelva FALSE */
while(TRUE == GetMessage(&mensaje, NULL, 0, 0))
{
/* Traducir mensajes de teclas virtuales a mensajes de caracteres */
TranslateMessage(&mensaje);
/* Enviar mensaje al procedimiento de ventana */
DispatchMessage(&mensaje);
}
/* Salir con valor de retorno */
return mensaje.wParam;
}
/* Esta función es invocada por la función DispatchMessage() */
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance;
static int veces;
switch (msg) /* manipulador del mensaje */
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT)lParam)-> hInstance;
return 0;
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case CM_DIALOGO2:
//bucle
DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc2, veces);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */
break;
default: /* para los mensajes de los que no nos ocupamos */
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
BOOL CALLBACK DlgProc2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
char texto[25];
switch (msg) /* manipulador del mensaje */
{
case WM_INITDIALOG:
sprintf(texto, "Veces invocado: %d", (int)lParam);
SetWindowText(GetDlgItem(hDlg, TEXTO), texto);
return TRUE;
case WM_COMMAND:
EndDialog(hDlg, FALSE);
return TRUE;
}
return FALSE;
}
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net<mailto:Cconclase@listas.conclase.net>
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
Re: Duda con winapi (Salvador Pozo) 2018-10-21 15:06:01
El pasado 2018-10-21 12:56:59, ruben escribió:
Hola:
r> Estoy aprendiendo a usar winapi con el curso de cconclase y es realmente bueno.
Gracias, me alegra saber que te gusta.
r> Se me a presentado un problema que no tengo claro como gestionarlo. Estoy acostumbrado a programar en consola y cuando quieres hacer un bucle que tarde su tiempo, simplemente hay que esperar a que termine.
r> El caso es que si activo un bucle con WM_COMAND, la aplicación se cuelga hasta que el bucle finalice.
Las tareas de manipulación de mensajes, el procedimiento de ventana, deberían ejecutarse lo más rápidamente posible, precisamente para evitar que la aplicación se quede congelada durante mucho tiempo sin responder a las acciones del usuario.
Cuando una tarea requiera un tiempo apreciable para completarse se debería asignar a un cuadro de diálogo o a un hilo (thread) paralelo, o a un conjunto de ambas cosas.
Ejemplos de este tipo de tareas son las copias de archivos, descargas desde la red o instalación de aplicaciones.
Ayuda mucho en estos casos mostrar barras de progresos y mensajes que den información para que el usuario sepa que las tareas se están llevando a término con normalidad (o que no, en caso de que haya algún problema).
La respuesta a tu problema son los hilos. Puedes ver una primera aproximación en este enlace:
http://articulos.conclase.net/?tema=juegos&art=threads&pag=000
Como los hilos pueden compartir memoria con el programa que los ha creado, es relativamente sencillo compartir información entre el procedimiento de ventana y los hilos, de modo que se pueda monitorizar el avance de las tareas realizadas por cada hilo.
Espero que te sirva de ayuda, pregunta de nuevo si necesitas alguna aclaración.
Hasta pronto.
--
Salvador Pozo (Administrador)
mailto:salvador@conclase.net
Blog con Clase: http://blogconclase.wordpress.com
Con Clase: http://conclase.net
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
Re: Duda con winapi (ruben) 2018-10-22 02:40:36
Buenas Salvador,
Lo de los hilos es perfecto. Sencillo y muy útil.
Para este caso lo necesito para descargar registros de una API y lo de la barra de progreso va a ser bastante útil también.
Lo que haré será poner un bool en cada parámetro del WD_COMAND y crearé una función para gestionar todos los hilos según los bool estén a 0 o a 1.
Gracias otra vez ;D
Un saludo
________________________________
De: Cconclase <cconclase-bounces@listas.conclase.net> en nombre de Salvador Pozo <salvador@conclase.net>
Enviado: domingo, 21 de octubre de 2018 17:06
Para: cconclase@listas.conclase.net
Asunto: Re: [C con Clase] Duda con winapi
El pasado 2018-10-21 12:56:59, ruben escribió:
Hola:
r> Estoy aprendiendo a usar winapi con el curso de cconclase y es realmente bueno.
Gracias, me alegra saber que te gusta.
r> Se me a presentado un problema que no tengo claro como gestionarlo. Estoy acostumbrado a programar en consola y cuando quieres hacer un bucle que tarde su tiempo, simplemente hay que esperar a que termine.
r> El caso es que si activo un bucle con WM_COMAND, la aplicación se cuelga hasta que el bucle finalice.
Las tareas de manipulación de mensajes, el procedimiento de ventana, deberían ejecutarse lo más rápidamente posible, precisamente para evitar que la aplicación se quede congelada durante mucho tiempo sin responder a las acciones del usuario.
Cuando una tarea requiera un tiempo apreciable para completarse se debería asignar a un cuadro de diálogo o a un hilo (thread) paralelo, o a un conjunto de ambas cosas.
Ejemplos de este tipo de tareas son las copias de archivos, descargas desde la red o instalación de aplicaciones.
Ayuda mucho en estos casos mostrar barras de progresos y mensajes que den información para que el usuario sepa que las tareas se están llevando a término con normalidad (o que no, en caso de que haya algún problema).
La respuesta a tu problema son los hilos. Puedes ver una primera aproximación en este enlace:
http://articulos.conclase.net/?tema=juegos&art=threads&pag=000
Artículos con Clase - Usar varios hilos en la programación ...<http://articulos.conclase.net/?tema=juegos&art=threads&pag=000>
articulos.conclase.net
Lo primero que tenemos que tener en cuenta es que un hilo es un recurso. Cada vez que creemos un hilo, el sistema creará un manipulador al que irá asociado el hilo, pero también reservará otros recursos, como una pila, memoria, etc. Es responsabilidad nuestra liberar esos recursos cuando ya no los necesitemos.
Como los hilos pueden compartir memoria con el programa que los ha creado, es relativamente sencillo compartir información entre el procedimiento de ventana y los hilos, de modo que se pueda monitorizar el avance de las tareas realizadas por cada hilo.
Espero que te sirva de ayuda, pregunta de nuevo si necesitas alguna aclaración.
Hasta pronto.
--
Salvador Pozo (Administrador)
mailto:salvador@conclase.net
Blog con Clase: http://blogconclase.wordpress.com
Con Clase: http://conclase.net
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
_______________________________________________
Lista de correo Cconclase Cconclase@listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ