PDA

Ver la Versión Completa : Bloquear aplicacion despues de cierto tiempo


Marcela
24-05-2003, 00:25:02
Como hago para saber cuando el aplicativo no ha sido usado por un determinado periodo de tiempo para asi poder controlar al usuario para desconectarlo de la base de datos y cerrar la aplicación automaticamente. Esto con fin de controlar que el usuario no deje la aplicacion abierta y se vaya.

Gracias

Marcela

andres1569
24-05-2003, 12:59:01
Hola:

Puedes colocar un componente TApplicationEvents, interceptar el evento OnIdle y ahí almacenas en una variable de tipo Longint el instante mediante GetTickCount. Colocas un TTimer con un Interval no muy pequeño, puesto que debe controlar minutos supongo (p.e. Interval = 60000), y ahí compruebas si ha trnscurrido el máximo tiempo de inactividad, algo así:



var
UltimoAcceso : Longint;

procedure TFormPrincipal.ApplicationEvents1OnIdle (Sender: TObject;
var Done: Boolean);
begin
UltimoAcceso := GetTickCount;
Done := TRUE;
end;

procedure Timer1OnTimer (Sender: TObject)
begin
if GetTickCount - UltimoAcceso > 3600000 then // 60 minutos
Database1.Connected := FALSE;
end;


Si manejas un Delphi 4.0 o menor, no exite el componente TApplicationEvents, tienes que hacerlo "a mano":


procedure TFormPrincipal.AppMessage (var Msg:TMsg; var Handled:Boolean);
begin
// interceptamos eventos de teclado y ratón
if (Msg.message in [WM_KEYFIRST .. WM_KEYLAST]) OR
(Msg.message in [WM_MOUSEFIRST .. WM_MOUSELAST]) then
UltimoAcceso := GetTickCount;
end;

procedure TFormPrincipal.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
UltimoAcceso := GetTickCount;
end;


A ver si esto te sirve

Un saludo

Marcela
06-06-2003, 22:04:05
No encuentro el componente TApplicationEvents y estoy trabajando en Borland Delphi 6 Entreprise, te agradeceria me pudieran decir donde se encuentra y si no lo tengo instalado como podria instalarlo.

Gracias.
:confused:

__marcsc
06-06-2003, 22:12:12
En la paleta additional :cool:

Saludos

andres1569
06-06-2003, 22:26:33
Hola Marcela:

Gracias por reaparecer. Hace ya 10 días que te contesté y no sabía cómo había ido la cosa. Si el tiempo de inactividad que le vas programar al usuario es similar al que has tardado en contestar, puedes sustituir el 360000 del ejemplo que te mandé por un Googol. :) :) :)

Por favor, no te molestes por esto, es una broma, si has vuelto a los foros despues de estos días, te recomiendo que te pases por la sección de humor, últimamente se ha vuelto la gente muy chistosa.

Mira esto: http://www.clubdelphi.com/foros/showthread.php?s=&threadid=1119

Saludos y ya nos contarás si funciona como quieres o no.

Marcela
19-06-2003, 01:56:25
Muchisimas gracias, me funciono lo que andres1569 me dijo, disculpemen por no haber podido contestar antes.

Marcela :D

Lepe
03-07-2003, 22:00:23
Hola, ya que está este hilo, pues aprovecho para preguntar esto mismo pero en Windows XP ya que GetTickCount tiene problemas en ese sistema :(

Windows NT: To obtain the time elapsed since the computer was started, look up the System Up Time counter in the performance data in the registry key HKEY_PERFORMANCE_DATA. The value returned is an 8 byte value.

¿alguien entiende como leer esa clave?? porque yo no entiendo si está en Current_User o Local_Machine del registro de windows :confused:

andres1569
03-07-2003, 22:54:06
Hola Lepe, no sabía de esa limitación del XP, si es que parece que vamos hacia atrás, estoy seguro de que hay miles de aplicaciones por ahí que usan esa GetTickCount.

De todas formas, no creo que sea buena idea consultar una clave del registro para averiguar un espacio de tiempo, imagínate el tiempo que pasa desde que pides el valor hasta que lo encuentra :) :)

Si miras en este truco de Ian Marteens, verás una forma de acceder a un reloj de alta precisión y que parece encontrarse en cualquier hardware:

http://www.marteens.com/trick4c.htm

Por el nombre de la función, QueryPerformanceCounter, debe guardar cierta relación con la clave del registro que tu comentas, es posiblñe que Windows actualice ese valor a partir de dicha función, pero me extraña todo esto de que haya que mirarlo en el registro, muy raro me parece.

Lepe
04-07-2003, 17:50:42
Gracias por contestar andres, si quieres leer eso que puse en inglés, consulta la ayuda de gettickcount en delphi, abajo del todo pone eso.

Puede que lo haya malinterpretado, no sé, pero es lo que me pareció al leer la ayuda :confused: aunque confieso que no entendí ciertas palabras en ingles :o

Por otra parte, he observado que en la aplicación se producen eventos OnIdle muy frecuentemente por lo que reinicia el valor UlimoAcceso que tu proponias. Para realizar las pruebas, en el evento OnTimer1 le dije que me pusiese en la barra de estado la diferencia Gettickcount - UltimoAcceso y como máximo obtuve una diferencia de 400 milisegundos.

El timer tenia un Intervalo de 10.000 milisegundos ¿demasiado bajo para funcionar?

Si no es mucha molestia te rogaria que compruebes si funciona el uso de OnIdle junto con lo del timer, porque me da la impresión de que no es posible hacerlo así. (Ojalá me equivoque :D)

En cuanto al maestro Ian Marteens, me pongo manos a la obra ahora mismo.


Gracias por contestar. Un saludote de tu pupilo menos aventajado :P

andres1569
04-07-2003, 21:27:23
Hola:

Tienes, razón, Lepe, ni siquiera lo probé en su día, y lo que me extraña es que le haya funcionado a Marcela, salvo si lo ha hecho con Delphi 4.0 o anterior. El evento OnIdle no es el más apropiado porque la aplicación recibe constantemente mensajes de todo tipo (de reloj, de repintado y otros internos ...) y a continuación, cuando no tiene qué hacer dispara este evento. He comprobado, como tú, que se dispara con demasiada frecuencia, no como yo pensaba.

Lo correcto es interceptar el evento OnMessage de TApplicationEvents y meter ahí el código que ya puse para la versión Delphi 4.0, es decir, chequear si se ha producido un mensaje de teclado o de ratón, que son los más normales de un usuario.

Otro error que he detectado es en la forma de comprobar si el mensaje es de teclado o de ratón, no vale usar un rango de constantes aquí, así que hay que sustituir:

(Msg.message in [WM_KEYFIRST .. WM_KEYLAST])
por
(Msg.message >= WM_KEYFIRST) AND (Msg.message <= WM_KEYLAST)

Lo mismo para los mensajes del mouse.

Todo quedaría así, para quien lo quiera usar, y que se olvide de lo anterior:

var
UltimoAcceso: Longint; // variable global

procedure TForm1.FormCreate(Sender: TObject);
begin
UltimoAcceso := GetTickCount;
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
// interceptamos eventos de teclado y ratón
if ((Msg.message >= WM_KEYFIRST) AND (Msg.message <= WM_KEYLAST)) OR
((Msg.message >= WM_MOUSEFIRST) AND (Msg.message <= WM_MOUSELAST)) then
UltimoAcceso := GetTickCount;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if GetTickCount - UltimoAcceso > 3600000 then // 60 minutos
Database1.Connected := FALSE;
end;

Esto ya está probado y cumple su cometido.

Lo de la clave de registro HKEY_PERFORMANCE_DATA en WinNT, yo he leído lo mismo que tú, por lo visto en esa clave del registro se almacena el tiempo transcurrido desde el arranque de Windows, lo que no sé es con qué frecuencia se actualiza ese valor. De lo que no me cabe duda es que no es un buen sistema para estar llamándolo constantemente, no es lo mismo llamar a una función como GetTickCount que está ya cargada en memoria (en su DLL correspondiente), que acceder a un fichero de varios megas para localizar ese valor.

Dijiste: Un saludote de tu pupilo menos aventajado
Digo yo: Mejor no seas pupilo de alguien que mete la pata de esta forma :) . Todos aprendemos de todos :)

Lepe
05-07-2003, 11:47:50
Muchas gracias por contestar con tanta rapidez y eficiencia andres.


Lo de la clave de registro... casi mejor nos olvidamos de elllo y dejemos que Microsoft siga usando su amado registro de Windows ;) Nosotros usaremos otras alternativas :D


Dijiste: Mejor no seas pupilo de alguien que mete la pata de esta forma :)

Digo yo: Nunca habia usado los applicationsEvents hasta ahora, así me obligaste a leerme la ayuda; tambien esa es una forma de enseñar-aprender ;)

Dijiste: Todos aprendemos de todos
Y además es una muy buena forma de ampliar los horizontes abriendo la mente a ideas que a uno solo no se le hubiese ocurrido en la vida.

Un saludo Maestro :)

sebas
07-07-2003, 13:47:10
Hola a todos, soy nuevo en el foro y me gustaria me ayudaran con éste tema también.

Estuve probando la funcion ApplicationEvents1OnIdle con el "Timer" y primero que nada a que se refiere exatamente el "Idle" y segundo, esta funcion se ejecuta por cualquier movimiento del mouse o bien porque el cursor esta titilando en algún edit "esto es justamente lo que quiero evitar".

Yo tengo un sistema del cual no tengo los fuentes y este si en 5 minutos no das click en alguna parte del sistema o no apretas alguna techa dentro del sistema, envia un aviso de no uso del sistema y sale del mismo; esto mismo es lo que quiero hacer yo pero con la funcion ApplicationEvents1OnIdle incluso resetea el tiempo transcurrido cuando se mueve el mouse o titila el cursor.

Me pueden ayudar, y gracias.

andres1569
07-07-2003, 14:32:55
Hola Sebas:

Tres mensajes antes que éste que estás leyendo y dos antes del que tu escribiste, he puesto la forma correcta de hacer esto que pides.

En realidad, el evento OnIdle (que significa en espera) no es el más adecuado para saber cuándo una aplicación deja de recibir órdenes, no es que se dispare cuando se procesa un mensaje, sino justo después de realizar cualquier acción por parte de la aplicación, la pega es que se dispara con demasiada frecuencia (en mi primer post lo utilicé porque creía que no), puesto que la aplicación recibe continuamente mensajes de todo tipo, sobre todo mensajes de reloj.

Mira el nuevo código, utilizando el evento OnMessage, y no debería darte problemas.

sebas
08-07-2003, 16:40:05
Muchas gracias Andres, esto funciona a la perfeccion; ahora solo tengo una duda a raiz de esto, dentro de mi sistema tengo algunos programas que ejecutan procesos SQL o copias de archivos y verificacion de archivos de texto, cuando se esta ejecutando uno de estos procesos, tanto el "reloj" que tengo dentro del sistema como el "timer" que verifica el GetTickCount quedan parados hasta tanto termine de ejecutarse dichos procesos, esto hace que si el proceso dura más de cinco minutos tiempo en el cual quiero que se cierre el sistema, automaticamente termina el proceso y se cierra el sistema porque el tiempo transcurrido entre el ultimo acceso y el nuevo son mayores a cinco minutos.

Como hago si es que se puede y me supongo que si; para que todo el tiempo se ejecute tanto el "timer" de verificacion como el "timer" del reloj digamos en background..

Sea como sea, espero tus comentarios.

andres1569
08-07-2003, 17:32:30
Para que tu aplicación siga chequeando la cola de mensajes, necesitas llamar de vez en cuando al método Application.ProcessMessages. Esta llamada la deberás poner dentro del bucle donde realices tus operaciones, siempre y cuando te sea posible intercalar esta orden en medio de los procesos que realices; aunque si éstos son operaciones del servidor, mucho me temo que tendrás que esperar a que el servidor termine; me consta que algunos servidores de BD permiten pasarles funciones tipo Callback para controlar la evolución de los procesos, consultas y demás, y así es posible por ejemplo mostrar una barra de progreso al usuario.
while not condicion do
begin
... tu proceso
Application.ProcessMessages;
end;
Otra posible solución es que dichos procesos los ejecutes dentro de un thread aparte (aparte del thread general de la aplicación), de esta forma, aunque no llames a ProcessMessages, la aplicación siempre tendrá su momento de reloj para despachar mensajes.

sebas
08-07-2003, 20:12:02
Andres, gracias por la ayuda, bueno al final para solucionar mi problema, voy a poner al final de cada proceso una llamada al processmessages asi no tendre problemas; pero me queda una duda; yo tengo un menu desplegable y cuando lo abro y recorro con el mouse la lista completa del menu, el .onmessage no es llamado por lo tanto el timer no es actualizado, sabes porque ocurre esto!!

Otra cosa como funciona este tema del "thread" podrias darme un ejemplo de como utilizarlo.

andres1569
10-07-2003, 21:19:53
Hola:

Sebas, leí tu mensaje hace días, pero ya me temía que llevaría un ratillo de sacar esto. He comprobado que es cierto lo que tú dices, si desplegamos un menú y movemos el ratón sobre él, no se dispara el evento OnMessage del ApplicationEvents, por lo tanto, no se reinicia el contador. Me temo que esto se debe a que los menús son controles que Delphi no implementa directamente sino que delega en Windows, y una vez que se muestran, los eventos que suceden sobre ellos no son capturados por la aplicación, salvo cuando el usuario hace click sobre una opción.

En definitiva, me he decidido a implementarlo mediante Hooks de ratón y de teclado y ha dado buen resultado. Reconozco que nunca había usado este recurso de programación, aunque había oído hablar de ellos bastantes veces. Básicamente se trata de registrar en Windows unas funciones que se interponen entre los eventos y nuestra aplicación, como una capa intermedia. Hay varios tipos de Hooks, para lo que nos preocupa capturamos sólo los que tienen que ver con acciones directas del usuario. Éste es el código nuevo, donde ya podemos olvidarnos del componente TApplicationEvents y del evento OnMessage (por cierto ya vamos por la versión 2.0 de este código, release 5, quien tenga la versión 1.0 que se baje el Update Pack 1 :D :D :D ):
var
Form1: TForm1;
UltimoAcceso : Longint; // variable global
HookHandleTec : hHook = 0; // Hook de teclado
HookHandleRat : hHook = 0; // Hook de ratón

implementation

{$R *.DFM}

// ésta es la función Callback que instalamos para controlar eventos de teclado
function CapturaMensajesTeclado (Code: Integer; wParam, lParam: Longint)
: Longint; stdcall;
begin
Case Code of
HC_ACTION,
HC_NOREMOVE : begin
UltimoAcceso := GetTickCount;
result := 0;
end
else result := CallNextHookEx (WH_KEYBOARD, Code, wParam, lParam);
end;
end;

// ésta es la función Callback que instalamos para controlar eventos del mouse
function CapturaMensajesRaton (Code: Integer; wParam, lParam: Longint)
: Longint; stdcall;
begin
Case Code of
HC_ACTION,
HC_NOREMOVE : begin
UltimoAcceso := GetTickCount;
result := 0;
end
else result := CallNextHookEx (WH_MOUSE, Code, wParam, lParam);
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
// inicializamos el Contador de tiempo y registramos en Windows las funciones Hook
UltimoAcceso := GetTickCount;
HookHandleTec := SetWindowsHookEx (WH_KEYBOARD, CapturaMensajesTeclado, hInstance, 0);
HookHandleRat := SetWindowsHookEx (WH_MOUSE, CapturaMensajesRaton, hInstance, 0);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
// si se llega al tope previsto, se muestra un mensaje
if GetTickCount - UltimoAcceso > 10000 then
begin
UltimoAcceso := GetTickCount; // reinicalizamos el contador, sólo para pruebas
ShowMessage('Tiempo excedido');
end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
// Liberamos los Hooks
UnHookWindowsHookEx (HookHandleTec);
UnHookWindowsHookEx (HookHandleRat);
end;
Como veis, ha cambiado la forma de hacerlo, pero la filosofía es la misma. Ahora, las notificaciones de eventos de usuario no nos vienen desde la aplicación sino que las notifica el mismo Windows.

Por cierto, los Hooks que instala una aplicación, como los del ejemplo, afectan al thread de la aplicación, de modo que si el usuario se pone a jugar al Solitario sin pasar el ratón por encima de nuestro programa, nuestro contador seguirá contando como si estuviera inactivo. Si se quisiera controlar a nivel del sistema, para asegurarse de que el usuario realmente no está actuando con la máquina, habría que registrar los Hooks desde una DLL, que cargaríamos al arrancar nuestra aplicación. De esa forma, los Hooks afectarían a todas las aplicaciones (threads) que tuviéramos activas en ese moneto. Si tenéis acceso a la "Guía de Desarrollo en Delphi X", de Teixeira y Pacheco, ahí viene muy bien explicado cómo usar los Hooks. En la DDG 5 está en la pag. 665.

Respecto a lo de los threads los ejemplos que te puedo poner son sacados de libros. Si no tienes ninguno a mano, te los posteo en otro mensaje (ahora dame un respiro :) ). En concreto tengo aquí un ejemplo bastante bueno de Marco Cantú, libro "Mastering Delphi 4.0", pag. 925, donde aplica un thread para realizar una operación sobre una tabla. Para usar un thread, básicamente, hay que crear una clase derivada de TThread y redefinir el método Execute, donde irá el código que quieres que se ejecute "separadamente" del resto. Luego, en el momento que creas el TThread, Delphi ya se encarga de registrarlo en la lista de hilos de Windows y de que se ejecute el código que le has programado. Imagino que en cualquier libro de Delphi debe venir algo sobre el asunto.

Saludos

guillotmarc
10-07-2003, 22:11:05
Hola.

¿ No sería más sencillo en lugar de mirar periodicamente el intervalo de tiempo desde la ultima acción, simplemente resetear el timer a cada evento ?. De forma que si el Timer llega a provocar un evento es porqué hemos superado los 5 minutos, y tenemos que bloquear la aplicación. Es más sencillo y no dependemos del funcionamiento del GetTickCount.

Versión 3.0 :D :D :


Al iniciar la aplicación configuramos y arrancamos el Timer para 5 minutos.
En el evento de AppEvents, reseteamos el Timer (poniendo el Enabled a False para volverlo a poner a True).
En el evento del Timer, bloqueamos la aplicación (puesto que solo podemos haber llegado tras 5 minutos de inactividad).


NOTA : También podemos aprovechar igualmente la magnífica detección de eventos propuesta por Andrés, en lugar de utilizar el AppEvents.

Saludos.

andres1569
10-07-2003, 22:51:35
Hola:

Guillotmarc, la idea que propones es elegante pero tiene un inconveniente si decidimos utilizar lo de los Hooks:

Las funciones callback que pasamos al Hook no son funciones de objetos, sino funciones "sueltas", por lo que no sé cómo en el cuerpo de estas funciones podríamos acceder a los TTimers (podríamos acceder a ellos mediante la expresión Form1.Timer.Enabled := FALSE, es decir referenciando la variable Form1, pero esto puede ser algo peligroso). Aunque a decir verdad las funciones Hooks siempre irán en el Form principal o en el DataModule principal, que normalmente estará activo durante toda la vida del programa, pero se debe tener en cuenta esa cuestión.

De todas formas, el llamar a GetTickCount creo que es más eficiente que poner Timer1.Enabled := FALSE y luego TRUE, puesto que al hacer esto se mata el Timer (KillTimer) y luego se vuelve a reservar. Esto quizás sea más lento. Ten en cuenta que si se está escribiendo o moviendo el ratón continuamente se estará ejecutando ese código repetidamente.

En realidad, si queremos aplicar un tiempo de espera de más de un cuarto de hora, por ejemplo, el Timer lo podemos poner a un intervalo de 1 minuto (60000) y no repercutirá mucho en la marcha de la aplicación.

guillotmarc
11-07-2003, 00:31:14
Hola.

Posteado originalmente por andres1569
Las funciones callback que pasamos al Hook no son funciones de objetos, sino funciones "sueltas", por lo que no sé cómo en el cuerpo de estas funciones podríamos acceder a los TTimers (podríamos acceder a ellos mediante la expresión Form1.Timer.Enabled := FALSE, es decir referenciando la variable Form1, pero esto puede ser algo peligroso). Aunque a decir verdad las funciones Hooks siempre irán en el Form principal o en el DataModule principal, que normalmente estará activo durante toda la vida del programa, pero se debe tener en cuenta esa cuestión.

No creo realmente que hubiese problemas, es lo mismo que acceder a la variable UltimoAcceso que estará definido en el formulario principal, también tenemos que poner el Timer en ese formulario. Así aseguramos que el tiempo de vida del Timer sea el mismo que las llamadas a los Hooks. Si hubiera la posiblidad de que se ejecutarán en threads distintos si que habría que sincronizar (hay una función para eso) el acceso al Timer para asegurar que no se provoque un conflicto, pero no es el caso.

Posteado originalmente por andres1569
De todas formas, el llamar a GetTickCount creo que es más eficiente que poner Timer1.Enabled := FALSE y luego TRUE

Completamente de acuerdo, aunque lo que tienes que comparar són la ejecución de tu función garfio, con el reseteo que propongo yo. Para el tema del rendimiento nos podemos olvidar de los disparos de los timers, en mi solución, simplemente porqué nunca se dispara, y en la tuya, porqué como dices, se puede definir para intervalos suficientemente largos como para despreciarlo.

Esta claro que poner en la función garfio un acceso a GetTickCount es más eficiente que resetear el Timer. No he propuesto esa solución por rendimiento, sinó como comentas, por la elegancia de solucionar el problema unicamente con dos componentes y dos lineas de código. (El rendimiento no siempre lo es todo).

Un saludo.

andres1569
11-07-2003, 11:02:13
Hola Marc:

Quizás me expresé mal en la primera consideración; a lo que me refería con lo de acceder a los Timers no era por una cuestión del tiempo de vida de los mismos sino a que el Timer está declarado dentro de la clase TForm, mientras que la variable UltimoAcceso es global. Si escribimos Form1.Timer.Enebled, esto nos obliga a que Form1 esté creado (lo cual es cierto normalmente si Form1 está en la lista de AutoCreate Forms), pero esta asignación no funcionaría si Form1 fuera nil. Este es un problema general que se nos presenta cuando queremos acceder a componentes de un Form desde funciones que no pertenecen a la declaración de dicho form, tenemos que referirnoa a variables que no sabemos si se van a instanciar o no. Admito, de todas formas, que lo normal es que esto no suceda si hablamos del Form principal o del DataModule principal, que suelen instanciarse una vez (usando la variable declarada en su unit) y de forma automática al arrancar el programa.

Tanto en las dos soluciones que planteamos, una cosa parece clara, a cada evento de usuario se dispara, o bien en tu caso Timer.Enabled o como yo proponía GetTickCount, si es que lo entendí bien. En este caso, teniendo en cuenta la frecuencia con que se disparan los eventos (más sabiendo que hay eventos del mouse), creo que el rendimiento sí es fundamental.

Ahora se me ha ocurrido una forma de hacerlo que quizás no te agrade demasiado, porque declara 2 variables más, y es algo inexacta; la ventaja es que no entorpece la aplicación con llamada a métodos, lo cual puede ser crítico cuando se dan muchos eventos consecutivos (claro que con las máquinas de hoy quizás eso no se note demasiado):

1.- Declaramos dos nuevas variables globales, EventoOcurrido : Boolean, y TiempoTranscurrido : Longint;

2.- Cuando se produce un evento (ya sea con AppEvents o con Hooks), ponemos EventoOcurrido a TRUE;

3.- El TTimer lo fijamos a un intervalo de 10000 (10 segundos no afecta mucho a la aplicación), éste intervalo será el que marque la inexactitud.

4.- En el OnTimer del Timer escribimos algo así:
if EventoOcurrido then
begin
EventoOcurrido := FALSE;
TiempoTranscurrido := 0;
end
else begin
Inc (TiempoTranscurrido, Timer1.Interval);
if TiempoTranscurrido > 3600000 then DeconectarAplicacion
end;
Con esto nos evitamos el uso del GetTickCount y sus efectos secundarios, aunque tenga cierto margen de error, que no creo que importe demasiado en muchos casos.
Podríamos bautizarla como versión remix, v. 3.2 (si te parece, nombre interno Guillot1569). :D:D

Son ideas ... que cada uno escoja la que má le guste.

PD: Para los interesados comentar que el proyecto "Código Bloquear Aplicación después de cierto tiempo" está sujeto a la especificación GPL, todo el que quiera puede participar. :)

kinobi
11-07-2003, 11:45:06
Hola,

Posteado originalmente por andres1569
PD: Para los interesados comentar que el proyecto "Código Bloquear Aplicación después de cierto tiempo" está sujeto a la especificación GPL, todo el que quiera puede participar. :)

si está bajo licencia GPL, sería conveniente aclarar que allí donde se utilice (la aplicación que utiliza "Bloquear Aplicación después de cierto tiempo") también debe estar bajo los términos de la licencia GPL, y por tanto los fuentes deben estar a libre disposición pública.

Tal vez otro tipo de licencias: BSD, MPL, o incluso LGPL, pudiesen ser no tan exigentes al respecto.

Saludos.

guillotmarc
11-07-2003, 18:13:28
Hola Andrés.

En efecto esta solución parece insuperable. Puesto que lo único que hacemos en el evento de usuario, es poner a cierto una variable booleana. :)

NOTA : Ni había pensado en la posiblidad que la variable UltimoAcceso fuese global. Es que nunca las uso, había pensado que sería una variable privada del formulario principal o del Datamodule principal, por eso comenté que el Timer tenia los mismos problemas de visibilidad y tiempo de vida que la variable.


si está bajo licencia GPL, sería conveniente aclarar que allí donde se utilice (la aplicación que utiliza "Bloquear Aplicación después de cierto tiempo") también debe estar bajo los términos de la licencia GPL, y por tanto los fuentes deben estar a libre disposición pública.


Parece que habría que ir pensando en hacer una licencia cdPL (club delphi public license), derivada de la GPL, para solventar estos problemas :D :D

Saludos.

Lepe
12-07-2003, 14:55:36
Hola a todos.

Siento no haber contestado antes, pero estoy mas liado que un gato con un obillo de lana.


Al final lo he implementado como tu dices andres, pero ahorrandome esas variables.

he creado una rutina que se llama Actualiza ultimo acceso

procedure TDTM.ActualizaUltimoAcceso();
begin
// bloqueo implementado mediante timer

Timer1.Interval:= gl.Bloqueo.Minutos*60000;
timer1.Enabled:=gl.Bloqueo.AutoBlock ;
end;

captando los mensajes de la aplicación

if ((Msg.message >= WM_KEYFIRST) AND (Msg.message <= WM_KEYLAST)) OR
((Msg.message >= WM_MOUSEFIRST) AND (Msg.message <= WM_MOUSELAST)) then
dtm.ActualizaUltimoAcceso ;


Así lo que hago es reiniciar el timer con el tiempo que haya establecido el usuario. Se supone que esas instrucciones las hará cuando el usuario no esté haciendo nada, y son solo 2 instrucciones.

Por otra parte, el Ontimer se ejecutará 1 vez cada 4 o 5 minutos y lo unico que hace es presentar la pantalla de bloqueo deshabilitando el timer hasta que se vuelva a Reconectar el usuario.

Quizás esté recargando el Applicantion.OnMessage, pero me olvido de saber cuando ha sido el UltimoAcceso del Usuario y si ha ocurrido el Evento o no.


Como bien decias esta es otra idea, que cada cual coja la que mas le guste :cool:


SALUDOS A TODOS y MUCHAS GRACIAS por el interés que han prestado.

JuanPa1
21-09-2006, 17:55:18
Hola, tengo una interrogante. El tipo TMsg es de delphi y que hace?? hay un tipo equivalente en visual basic o algun componente que me permita hecer lo mismo en visual basic??
Cualquier sugerencia o respuesta a mi pregunta gracias de antemano
Saludos..

Hola:

Puedes colocar un componente TApplicationEvents, interceptar el evento OnIdle y ahí almacenas en una variable de tipo Longint el instante mediante GetTickCount. Colocas un TTimer con un Interval no muy pequeño, puesto que debe controlar minutos supongo (p.e. Interval = 60000), y ahí compruebas si ha trnscurrido el máximo tiempo de inactividad, algo así:



var
UltimoAcceso : Longint;

procedure TFormPrincipal.ApplicationEvents1OnIdle (Sender: TObject;
var Done: Boolean);
begin
UltimoAcceso := GetTickCount;
Done := TRUE;
end;

procedure Timer1OnTimer (Sender: TObject)
begin
if GetTickCount - UltimoAcceso > 3600000 then // 60 minutos
Database1.Connected := FALSE;
end;

Si manejas un Delphi 4.0 o menor, no exite el componente TApplicationEvents, tienes que hacerlo "a mano":


procedure TFormPrincipal.AppMessage (var Msg:TMsg; var Handled:Boolean);
begin
// interceptamos eventos de teclado y ratón
if (Msg.message in [WM_KEYFIRST .. WM_KEYLAST]) OR
(Msg.message in [WM_MOUSEFIRST .. WM_MOUSELAST]) then
UltimoAcceso := GetTickCount;
end;

procedure TFormPrincipal.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
UltimoAcceso := GetTickCount;
end;

A ver si esto te sirve

Un saludo

angelk3215
16-04-2017, 23:43:38
descarga la Cerradura AppLock es muy buena y es super liviana con esa seguro resuelves
bloqueodeaplicaciones.com

AgustinOrtu
16-04-2017, 23:47:23
descarga la Cerradura AppLock es muy buena y es super liviana con esa seguro resuelves
bloqueodeaplicaciones.com

Eso no es para Android?