Ver Mensaje Individual
  #16  
Antiguo 24-11-2015
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Reputación: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Gracias, Jhonny. De hecho son casi ochos años y un poquitín de vergüenza por volver a leer a aquel Al González.

Aprovecho para saludar a jachguate, de quien guardo hondos y buenos recuerdos, esperanzado en que sólo han de ser los primeros de muchos más. Y claro, Antonio, el código es libre, puedes mirar lo de echar mano en la línea de multi-hilos (perdón por el pequeño retraso ). Por cierto, aquello sigue pendiente, ya merito.

elliotduvorov: Toma muy en cuenta todo lo que te dice jachguate, comparto al 100% su opinión.

Es más, debo decir que tiempo después surgió una importante pifia en esa clase. Me permito copiar aquí una breve correspondencia que tuve con colega Delphi en noviembre de 2011, en la cual de describe el problema y se ofrece una probable solución. NOTA: Consideren que es información técnica informal, sin pruebas rigurosas de por medio. Lo pongo porque puede ser útil para quienes se interesen en encontrar una solución definitiva y elegante.

Cita:
Empezado por Martín
> Hola Al!
> Te molesto porque he intentado utilizar tu objeto en DelphiXE y dá resultados algo aleatorios según el código que vaya cambiando.
> El ejemplo con una sola aplicación, funciona sin problemas, incluso, he descargado el ejemplo que posteo otro usuario PruebaDBLogin, y funciona.
> Pero son aplicaciones con un solo form, y ejecuto siempre la misma.
>
> Si embargo, mi idea es controlar solamente que, si hay un usuario logueado (es practicamente un valor booleano + 2 string[64]), entonces no pide loguin nuevamente.
> Esta idea, se replica en cada uno de los ejecutables de una aplicación mayor.
> Tené presente que el sistema de usuario es muy básico, pero alcanza para los efectos que necesito.
>
> La prueba que hice, consisten en 2 aplicaciones, cada una de ellas es un ABM, y comparten, todo excepto el form del ABM y el form de edición.
> Si ejecutás la primer aplicación, funciona al pelo, y si vuelvo a ejecutarla, también.
> El problema se dá cuando ejecuto la otra aplicación... directamente no inicia. Si realizo un debug, me encuentro que se produce al crear el objeto global un error Runtime 216.
>
> Tenés idea por donde puede llegar a estar el problema?
> Desde ya, mil gracias!!!
Cita:
Empezado por Al González
Hola Martín.

Sí sé cuál es la causa del problema. Hace algunas semanas detecté la misma situación que describes. El error 216 (un "access violation") se debe al empleo de métodos virtuales, algo que en la descripción de la clase se sugiere evitar en caso de trabajar con instancias de ejecutables distintos.

Sucede que en las primeras versiones de Delphi no existía el método virtual AfterConstruction. Tuve conocimiento de él cuando empecé a utilizar Delphi 4, pero al momento de crear mi primer bosquejo de la clase (allá por el año 2003) no reparé en la existencia de este nuevo método y en su particular (y casi inevitable) marera de ser llamado: http://www.drbob42.com/delphi4/d4constr.htm

Viendo esta situación, desde que descubrí el problema me planteé escribir y publicar una nueva versión de la clase que salve esa incómoda situación. A grandes rasgos, la solución consistirá en la capacidad de crear instancias de objetos superglobales sin un constructor de por medio (llamando a NewInstance sin llamar a un método constructor formal), ya que, bajo la sintaxis estándar "Obj := Clase.Constructor" el método AfterConstruccion siempre es llamado, y esta llamada implícita, que en muchos casos resulta de lo más útil, viene a causar el problema cuando se usan estos objetos con instancias de diferentes EXEs.

Se explica porque una llamada a un método virtual se enlaza en tiempo de ejecución buscando la clase a la cual pertenece el objeto. El objeto guarda en sus primeros bytes dicha clase, que no es más que un puntero, sólo que ese puntero (una dirección de memoria) será válido para un ejecutable en particular, pero no necesariamente para los otros ejecutables que compartan el objeto. De ahí el error.

Espero subir pronto la solución a este problema, ¿qué tanto tiempo podrías esperarme?

Saludos.
Cita:
Empezado por Martín
Hola Al!
Ningún apuro. Entiendo cuál es el problema pero no podría hacer nada para ayudarte.
Mi línea de desarrollo es muy desktop contra base de datos, y el código de por sí, por muy comentariado que esté, supera todas mis posibilidades actuales.

Estoy en proceso de migrar un sistema que hace mucho está funcionando de Paradox a PostgresSQL (con Unidac), y de D7 a Dxe, y de paso quería agregarle algún control de usuario, y por otro lado, la posibilidad de mantener en la sesión del mismo, datos que me sirvan para “organizar” distintos ejecutables del mismo sistema.
Desde ya, que el tener el problema resuelto sería un ideal, pero puedo saltear esa funcionalidad por unos meses.

Si realmente te “interesa” tener un deadline para resolver algo que tenías ganas de resolver. Te lo agradezco, y por supuesto, como todo “cliente”, lo necesito para ayer!!!! Jejejejeje.
Si no está en tus planes inmediatos y futuros, despreocupate, buscaré alguna solución alternativa, o bien, no dispondré de la funcionalidad. No puedo esperar que “trabajes” para mi, aunque deduzco, que como me pasa a mi con muchas cosillas informáticas… es un reto a vencer!!! Jeje.

Desde ya, agradeciendo tu atención inmediata (fabuloso) y tu ofrecimiento, te envío muchos saludos, y quedo en espera de que me indiques si realmente es posible que puedas resolver la limitación…

GRACIAS!
Cita:
Empezado por Al González
Hola Martín.

Espero no hayas descartado aún el uso de la clase. Encontré una posible solución temporal, la cual no he probado, pero si mis nociones de Delphi no me fallan, lo único que tendrías que hacer es lo siguiente:

En lugar de la sintaxis

Obj := TMiClase.Create;

habría que usar

Obj := Pointer (TMiClase.NewInstance);

Y en lugar de

Obj.Free;

habría que usar

Obj.FreeInstance;

De esta manera se evitará que Delphi llame a los métodos virtuales AfterConstruction y BeforeDestruction. El inconveniente es que tendrás que prescindir de definir cualquier posible constructor o destructor en la nueva clase.

Por favor avísame si te resulta efectiva esta solución.

Muy buen día.
Cita:
Empezado por Martín
Hola!

No, no lo descarté para nada.

Tené presente que lo que necesito es solo mantener unos datos en la sesión de un usuario con estructuras básicas (shortstring, integer, boolean), no voy a necesitar nada parecido a un constructor o destructor.

Por lo que la solución temporal que proponés probablemente sea “definitiva” para mi propósito inmediato.



A tales efectos, sin hacer demasiadas pruebas, implementé lo que me indicás (te adjunto la unidad que mantendrá los datos locales de sesión), y obtuve los siguientes resultados:

- La solución completa con la creación y disposición del objeto como vos planteabas en el email anterior, en XP funciona sin problemas, en W7, no. Cerrás todas las aplicaciones y a veces pareciera que no se dispuso de los datos, y al cerrar, al rato, tira el error 216 (insisto, esto solo me pasó en W7 64bits). La compilación se hace para Win32, y el XP es 32b.

- Si elimino (como está ahora), en la unidad que te adjunto, el FreeInstance en el finalization, pareciera haberse solucionado el error.



De mi parte, con esto estaría más que solucionado, pero te ayudo con cualquier prueba que quieras realizar y tomaré en cuenta cualquier recomendación sobre el particular de no hacer el FreeInstance del objeto.



Saludos, buen fin de semana y Mil GRACIAS!!!
Un cordial saludo.

Al González.
Responder Con Cita