Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos


Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 12-02-2008
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.504
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Objetos superglobales

¡Hola a todos!

En los últimos días dediqué algunos ratos libres a escribir esta unidad de código. Es algo que programé hace varios años como parte de una biblioteca que contiene muchas otras cosas, pero decidí aislar y afinar este material para compartirlo con todos los colegas Delphi de manera más directa.

La idea básica es poder crearnos clases derivadas de una como TSuperGlobalObject en lugar de TObject, cuando queramos tener una instancia de objeto que pueda ser compartida entre procesos de manera natural y transparente.

Con esto, un programa Delphi en ejecución puede instanciar un objeto de clase definida por el programador, de la manera usual:
Código Delphi [-]
  O := TMiObjeto.Create;

Y luego otro programa Delphi en ejecución puede hacer lo mismo:
Código Delphi [-]
  O := TMiObjeto.Create;

En ese momento los dos procesos estarán compartiendo el mismo objeto, y podrán acceder a sus campos y métodos como lo harían con cualquier objeto normal. Los cambios que un programa hace sobre el objeto son automáticamente visibles para el otro programa. Esto resulta en una manera muy práctica de compartir información entre dos aplicaciones que se ejecutan en la misma máquina.

Pueden hacérsele muchas mejoras a esta unidad, como adaptarle semáforos de acceso para controlar escrituras simultáneas o modificar algunas secciones de su código para hacerla segura para hilos (thread safe), pero la base ya está.

Al final de este mensaje aparece un enlace para descargarla. He aquí su código (se aceptan críticas constructivas ):
Código Delphi [-]
Unit AGSuperglobals;

{ Unidad de la clase TSuperGlobalObject, base para instancias de objetos
  "superglobales".  Copyleft 2008 Al González.
  
  Web: http://rescatandoadelphi.blogspot.com/

  Esta unidad de código está generosamente comentada para facilitar el
  aprendizaje, pero puede utilizarse libremente en cualquier proyecto. }

Interface

  Type
    {*******************************************************************}
    { Clase TSuperGlobalObject.  Base para clases de objetos cuyas      }
    { instancias pueden ser compartidas entre procesos, a nivel del     }
    { sistema, de forma natural y transparente.  Emplea funciones de    }
    { mapeo de archivos ("file-mapping") de la API de Windows para      }
    { ubicar la instancia del objeto en memoria compartida.  Aprovecha  }
    { la virtualidad del método NewInstance para llevar a cabo tan      }
    { especial asignación de memoria.                                   }
    {                                                                   }
    { NOTA: Debido a que una instancia de objeto de este tipo es en sí  }
    { una vista mapeada ("mapped view") de memoria compartida a nivel   }
    { global del sistema operativo, su uso tiene varias limitaciones:   }
    {   1. Las clases descendientes no deben implementar interfaces.    }
    {   2. Las clases descendientes no deben contener campos que        }
    {      utilicen contadores de referencia, como son las cadenas      }
    {      largas (en lugar de éstas utilice ShortString o              }
    {      "String [n]"), los variantes, las interfaces y los arreglos  }
    {      dinámicos, ni tampoco punteros.                              }
    {   3. Solo podrán emplearse métodos virtuales o referencias        }
    {      (directas o indirectas) a la clase (ClassType) del objeto,   }
    {      cuando todos los procesos que lo compartan sean instancias   }
    {      del mismo módulo ejecutable.                                 }
    {                                                                   }
    { Debe tenerse en cuenta también que los métodos de un objeto de    }
    { memoria compartida, aunque pueden realizar modificaciones en los  }
    { valores de sus campos, su ejecución se lleva a cabo en el         }
    { contexto del proceso que los llama.                               }
    {*******************************************************************}
    TSuperGlobalObject = Class
      Public
        { Redefinimos estos dos métodos virtuales para ubicar a la nueva
          instancia de objeto en la memoria compartida de Windows y
          posteriormente liberar el espacio que ocupa cuando el objeto es
          destruido }
        Class Function NewInstance :TObject; Override;
        Procedure FreeInstance; Override;
    End;

    { Tipo clase de TSuperGlobalObject, auxiliar de la función
      CreateSuperGlobalObject }
    TSuperGlobalObjectClass = Class Of TSuperGlobalObject;

  { Funciones y procedimientos }

  { Función para crear una instancia de objeto superglobal identificándola
    con un nombre específico }
  Function CreateSuperGlobalObject (Const Cls :TSuperGlobalObjectClass;
    Const Name :String) :Pointer;

Implementation

  Uses
    Classes, Windows, SysUtils;

  Var
    { Lista de identificadores ("handles") dados por la API de Windows, uno
      por cada objeto de memoria compartida.  No podemos guardar el
      identificador de cada objeto en la instancia misma, porque Windows
      proporciona diferentes identificadores a cada proceso aunque se
      trate del mismo objeto compartido. }
    HandleList :TList;

    { Lo anterior hace que debamos mantener esta lista de todos los objetos
      superglobales, para determinar cuál es el identificador de cada
      instancia creada. }
    ObjectList :TList;

    { La función CreateSuperGlobalObject guarda en esta variable el nombre
      dado, para después ser usado por el método NewInstance }
    ObjectName :String;

  { TSuperGlobalObject }

  { Redefinición del método NewInstance para evitar que el objeto sea
    constituido con un bloque de memoria convencional, haciendo que su
    memoria sea una vista mapeada del archivo de paginación del sistema
    operativo }
  Class Function TSuperGlobalObject.NewInstance :TObject;
  Var
    AlreadyExists :Boolean;
    Handle :THandle;
    Name :String;
  Begin
    { Si esta instanciación fue a través de la función
      CreateSuperGlobalObject, tomar el nombre dado, de lo contrario tomar
      el nombre de la clase para el objeto de memoria compartida }
    If ObjectName <> '' Then
      Name := ObjectName
    Else
      Name := ClassName;

    { Crear el (u obtener acceso al) objeto Windows de memoria compartida
      con el tamaño de instancia y nombre correspondientes, agregándole a
      éste el sufijo ".mem" para evitar conflictos con otro tipo de objetos
      Windows que podrían tener el mismo nombre.  Es prudente darle a cada
      objeto Windows un sufijo según su tipo (memoria compartida, mutex,
      semáforo, etc.) }
    Handle := CreateFileMapping (Invalid_Handle_Value, Nil, Page_ReadWrite,
      0, InstanceSize, Pointer (Name + '.mem'));

    { Después de llamar a CreateFileMapping, GetLastError devuelve
      error_Already_Exists si el objeto compartido ya había sido creado por
      este u otro proceso.  Eso no es propiamente un error, pero sí un
      indicador muy útil. }
    AlreadyExists := GetLastError () = error_Already_Exists;

    If Handle <> 0 Then
    Begin
      { Crear una vista mapeada sobre la totalidad del objeto Windows de
        memoria compartida.  Esta vista será nuestra "nueva" instancia de
        objeto Delphi superglobal. }
      Result := MapViewOfFile (Handle, file_map_All_Access, 0, 0, 0);

      If Result <> Nil Then
      Begin
        { Si el objeto de memoria compartida no existía previamente,
          llamamos al método InitInstance más que nada para que éste le
          asigne la clase a la cual pertenece.  No lo llamamos
          incondicionalmente porque InitInstance también inicializa en
          ceros los bytes de la instancia dada, cosa que no debemos hacer
          en caso de que el objeto superglobal estuviera ya creado. }
        If Not AlreadyExists Then
          InitInstance (Result);

        { Crear las listas de identificadores y de objetos en caso de que
          aún no lo estén }
        If HandleList = Nil Then
        Begin
          HandleList := TList.Create;
          ObjectList := TList.Create;
        End;

        { Añadir a las listas la relación identificador-objeto }
        HandleList.Add (Pointer (Handle));
        ObjectList.Add (Result);

        Exit;
      End;
    End;

    { Elevar esta excepción en caso de fallar CreateFileMapping o
      MapViewOfFile }
    Raise Exception.CreateFmt (
      'Falló intento de crear objeto superglobal "%s".', [Name]);
  End;

  { Redefinición del método FreeInstance para liberar el objeto de memoria
    compartida }
  Procedure TSuperGlobalObject.FreeInstance;
  Var
    I :Integer;
  Begin
    { Liberar la vista mapeada }
    UnmapViewOfFile (Self);

    { Liberar la memoria compartida y eliminar su identificador de la
      lista HandleList }
    I := ObjectList.IndexOf (Self);
    CloseHandle (THandle (HandleList.Extract (HandleList [i])));

    { Eliminar la instancia de la lista ObjectList }
    ObjectList.Delete (I);

    { Destruir las listas HandleList y ObjectList si han quedado vacías }
    If HandleList.Count = 0 Then
    Begin
      FreeAndNil (HandleList);
      FreeAndNil (ObjectList);
    End;
  End;

  { Funciones y procedimientos }

  { Función auxiliar para crear instancias de objetos superglobales con
    nombres específicos.  El nombre no puede ser dado como parámetro de un
    constructor porque lo necesita el método NewInstance, el cual se
    ejecuta antes que los constructores. }
  Function CreateSuperGlobalObject (Const Cls :TSuperGlobalObjectClass;
    Const Name :String) :Pointer;
  Begin
    { Guardar en la variable ObjectName el nombre que usará
      TSuperGlobalObject.NewInstance en la siguiente instanciación }
    ObjectName := Name;

    Try
      { Crear el objeto superglobal }
      Result := Cls.Create;
    Finally
      { Limpiar la variable ObjectName para no afectar a otras
        instanciaciones que se realicen sin la ayuda de esta función }
      ObjectName := '';
    End;
  End;

End.

Espero que a alguien le sea de utilidad. Ojalá todo mi trabajo consistiese en hacer cosas como esta. Algún día no muy lejano...

Un abrazo superglobal.

Al González.
Archivos Adjuntos
Tipo de Archivo: zip AGSuperglobals.zip (3,1 KB, 169 visitas)
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117

Última edición por Al González fecha: 12-02-2008 a las 07:53:09.
Responder Con Cita
  #2  
Antiguo 12-02-2008
Avatar de Crandel
[Crandel] Crandel is offline
Miembro Premium
 
Registrado: May 2003
Ubicación: Parana, Argentina
Posts: 1.475
Poder: 17
Crandel Va por buen camino
Thumbs up Excelente

Excelente Al, pinta muy bueno . Cuando vuelva a casa del trabajo lo probare.
__________________
[Crandel]
Responder Con Cita
  #3  
Antiguo 12-02-2008
Avatar de dec
dec dec is offline
Moderador
 
Registrado: Dec 2004
Ubicación: Alcobendas, Madrid, España
Posts: 12.630
Poder: 27
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Tiene buena pinta, ¿no? No lo he probado (estoy perezoso) pero tiene buena pinta, me parece. Gracias Al.
__________________
David Esperalta
www.davidesperalta.com
Responder Con Cita
  #4  
Antiguo 12-02-2008
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Hola Al,
Cuanto vi el título sospeché un poco... me llamó la atención pues mi loco cerebro me decía, sin haber leído "¿Pero que no eso se consigue empleando un singleton?"

Fue mi sorpresa que al leer el hilo no se trataba de eso. Te debo una disculpa por haber dudado. Mil disculpas.

Algo de esa "teoria" me suena, desafortunadamente, a chino. Pues nunca he estado probando las API de mapeo (al menos que yo recuerde). Pero tu bien documentada unidad sirve de ejemplo para comprender mejor los conceptos.

Tiene una muy buena pinta. Tengo que probarla. No me puedo quedar sin las ganas de probarla.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #5  
Antiguo 12-02-2008
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: May 2003
Ubicación: Guatemala
Posts: 6.243
Poder: 22
jachguate Va por buen camino
Interesante idea Al... en mas de una ocasión se ha planteado la manera de compartir información entre dos procesos que se ejecutan en la misma máquina. Esta solución "nativa" de delphi me parece muy interesante. Ahora estoy lejos de mi máquina habitual de trabajo, pero haré algunas pruebas cuando esté de vuelta.

Creo que es básico el soporte multi-hilos. Se que ya lo has planteado, pero pido permiso para echar mano en esa línea, a ver si llego a algo bueno.

Un saludo.
__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #6  
Antiguo 12-02-2008
Avatar de Crandel
[Crandel] Crandel is offline
Miembro Premium
 
Registrado: May 2003
Ubicación: Parana, Argentina
Posts: 1.475
Poder: 17
Crandel Va por buen camino
Decirte que funciona de maravillas

Todavia la parte del mapeo no me queda muy claro, lo voy a tener que seguir analizando y buscando un poco mas de info, pero me gusto

Gracias
__________________
[Crandel]
Responder Con Cita
  #7  
Antiguo 05-01-2009
avmm2004 avmm2004 is offline
Miembro
 
Registrado: Jun 2006
Ubicación: Santa cruz de Tenerife, Islas Canarias
Posts: 482
Poder: 13
avmm2004 Va por buen camino
Cita:
Empezado por Crandel Ver Mensaje
Decirte que funciona de maravillas

Todavia la parte del mapeo no me queda muy claro, lo voy a tener que seguir analizando y buscando un poco mas de info, pero me gusto

Gracias
Hola Crandel, he estado mirando el código de Al gonzalez con respecto al Tsuperglobalobject y me supera en complejidad y conocimientos a pesar de lo bien comentada que está.

No tendrías algun ejemplo hecho que te funcione de como utilizarla a ver si me consigo aclarar.

Llevo unas cuantas horas con la Unit y me SUPERA.

gracias.
Responder Con Cita
  #8  
Antiguo 06-01-2009
Avatar de Crandel
[Crandel] Crandel is offline
Miembro Premium
 
Registrado: May 2003
Ubicación: Parana, Argentina
Posts: 1.475
Poder: 17
Crandel Va por buen camino
Hola avmm2004, aca te paso el ejemplo que escribi en aquel momento que lo probe, es muuuuy sencillo, simplemente escribe una variable en la memoria y la lee.

El programa esta en turbo delphi, pero no debería haber problema de compilarlo en otra versión.

Simplemente compila el programa y luego ejecuta varias instancias de mismo. Veras que puedes modificar el valor de la variable desde un programa y luego leerlo desde otro de forma transparente.
__________________
[Crandel]
Responder Con Cita
  #9  
Antiguo 06-01-2009
Avatar de Crandel
[Crandel] Crandel is offline
Miembro Premium
 
Registrado: May 2003
Ubicación: Parana, Argentina
Posts: 1.475
Poder: 17
Crandel Va por buen camino
Bueno ... me dio un poco de verguenza mandartelo asi no mas, todoqueteado como niño de primaria al código de nuestro amigo Al.

Asi que aca te dejo la versión limpia y prolija. Donde lo único que debes hacer es modificar la clase MySuperGlobalClass con lo que quieras y no tocar la clase de Al.


.
Archivos Adjuntos
Tipo de Archivo: zip superglobal.zip (6,1 KB, 84 visitas)
__________________
[Crandel]
Responder Con Cita
  #10  
Antiguo 20-11-2015
elliotduvorov elliotduvorov is offline
Registrado
 
Registrado: Sep 2008
Posts: 3
Poder: 0
elliotduvorov Va por buen camino
Buenas,

Para empezar perdón por el reflote...

Me ha surgido la necesidad de compartir objetos entre dos aplicaciones distintas, y he encontrado este hilo.

Mi duda:

El objeto que quiero compartir es un TORASession de los componentes ODAC de DevArt.

Mi idea seria hacer algo así:

Código Delphi [-]
TMiSuperObjetoSesion = Class(TSuperGlobalObject)
  Public
    MiSesion: TOraSession;
End;

Para después en cada aplicación hacer algo parecido a esto:

Código Delphi [-]
MiSesionLocal.AssignConnect(TMiSuperObjetoSesion.MiSesion);

Creéis que seria viable???

Gracias y un saludo.
Responder Con Cita
  #11  
Antiguo 20-11-2015
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: Jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 5.723
Poder: 19
Ñuño Martínez Va camino a la famaÑuño Martínez Va camino a la fama
Hola elliotduvorov, bienvenido al club. Como a todos los novatos, te invitamos a que revises la Guía de Estilo si no lo has hecho ya.

Respecto a tu pregunta, no estoy seguro de que vaya a funcionar ya que no creas ningún objeto. Realmente no he usado nunca este código, pero viendo el código adjuntado por Crandel, creo que deberías hacer algo así:
Código Delphi [-]
  TYPE
    TMiSuperObjetoSesion = CLASS (TSuperGlobalObject)
    PUBLIC
      MiSesion: TOraSession;
    END;

  VAR
    ElObjetoSesionGlobal: TMiSuperObjetoSesion;

  BEGIN
    ElObjetoSesionGlobal := TMiSuperObjetoSesion. Create;
    MiSesionLocal.AssignConnect (ElObjetoSesionGlobal.MiSesion)
  END

De todas formas, ten en cuenta las limitaciones de las que habla Al en la cabecera de su código, ya que el objeto "MiSesion" podría darte problemas. El artículo de la bitácora del máster Al incluye más información acerca del mecanismo, y dará pistas de qué se puede y qué no y por qué.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine

Última edición por Ñuño Martínez fecha: 20-11-2015 a las 17:55:34.
Responder Con Cita
  #12  
Antiguo 24-11-2015
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: May 2003
Ubicación: Guatemala
Posts: 6.243
Poder: 22
jachguate Va por buen camino
Cita:
Empezado por elliotduvorov Ver Mensaje
El objeto que quiero compartir es un TORASession de los componentes ODAC de DevArt.

Mi idea seria hacer algo así:

Código Delphi [-]
TMiSuperObjetoSesion = Class(TSuperGlobalObject)
  Public
    MiSesion: TOraSession;
End;

Para después en cada aplicación hacer algo parecido a esto:

Código Delphi [-]
MiSesionLocal.AssignConnect(TMiSuperObjetoSesion.MiSesion);
Si lees las premisas que expone Al sobre la implementación de TSuperGlobalObject te darás cuenta que este objeto reside en la memoria compartida.

Del curso Object Pascal 1.0, sabrás que las instancias de Objetos habitualmente viven en el Heap de tu aplicación, y que las variables de tipo objeto (TMyObject) son realmente un puntero a esta memoria.

De tal cuenta, en la aplicación donde originalmente creas la sesión, tendrás un puntero a una dirección de memoria válida, pero en cualquier otra aplicación que tenga acceso a este objeto super-global (incluso otra instancia de la misma aplicación) esa dirección a) puede no ser válida b) si lo es, definitivamente no residirá allí la instancia del objeto que esperas (lo cual es mucho peor).

Lo que se vislumbra es un Access Violation, o la corrupción de memoria de la segunda aplicación (la que no ha creado originalmente el sub-objeto MiSesion).

Dicho esto, aunque encontraras la forma de compartir la información de la sesión, la verdad no estoy seguro que se pueda compartir una sesión de Oracle entre varias aplicaciones, en todo caso habrá que revisar la documentación y el por qué quieres compartir la sesión antes de continuar.

Un saludo.
__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #13  
Antiguo 24-11-2015
Avatar de jhonny
jhonny jhonny is offline
Jhonny Suárez
 
Registrado: May 2003
Ubicación: Colombia
Posts: 7.031
Poder: 23
jhonny Va camino a la fama
Genial Al, muchas gracias por compartir. En la noche haré pruebas pero de entrada me ha llamado mucho la atención.
__________________
Lecciones de mi Madre. Tema: modificación del comportamiento, "Pará de actuar como tu padre!"

http://www.purodelphi.com/
http://www.nosolodelphi.com/
Responder Con Cita
  #14  
Antiguo 24-11-2015
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.173
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Cita:
Empezado por jhonny Ver Mensaje
En la noche
¿Esta noche o dentro de otros siete años?

// Saludos
Responder Con Cita
  #15  
Antiguo 24-11-2015
Avatar de jhonny
jhonny jhonny is offline
Jhonny Suárez
 
Registrado: May 2003
Ubicación: Colombia
Posts: 7.031
Poder: 23
jhonny Va camino a la fama
Cita:
Empezado por roman Ver Mensaje
¿Esta noche o dentro de otros siete años?

// Saludos
Esta , pues es que sólo hasta hoy me enteré
__________________
Lecciones de mi Madre. Tema: modificación del comportamiento, "Pará de actuar como tu padre!"

http://www.purodelphi.com/
http://www.nosolodelphi.com/
Responder Con Cita
  #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.504
Poder: 23
Al 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.
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117
Responder Con Cita
  #17  
Antiguo 25-11-2015
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: Jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 5.723
Poder: 19
Ñuño Martínez Va camino a la famaÑuño Martínez Va camino a la fama
¡Jachquate ha vuelto! ¿O quizá es que nunca te fuiste?

Al: Gracias por esa correspondencia.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine
Responder Con Cita
  #18  
Antiguo 09-05-2017
jars jars is offline
Miembro
 
Registrado: Mar 2004
Posts: 215
Poder: 15
jars Va por buen camino
Como es un hilo que tiene bastante tiempo espero que se pueda reactivar.
Estoy utilizando la clase de AL AGSuperGlobals para compartir en memoria un objeto entre distintas aplicaciones que contiene algunos datos del perfil del usuario logueado, para mantener un login único de las aplicaciones. Lo comparte todo bien pero al intentar liberar el objeto me da un access violation pese a haber usado la forma que sugiere AL: Obj.FreeInstance;
Alguna idea de como liberarlo?
Gracias.
Responder Con Cita
  #19  
Antiguo 31-08-2017
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.504
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por jars Ver Mensaje
Como es un hilo que tiene bastante tiempo espero que se pueda reactivar.
Estoy utilizando la clase de AL AGSuperGlobals para compartir en memoria un objeto entre distintas aplicaciones que contiene algunos datos del perfil del usuario logueado, para mantener un login único de las aplicaciones. Lo comparte todo bien pero al intentar liberar el objeto me da un access violation pese a haber usado la forma que sugiere AL: Obj.FreeInstance;
Alguna idea de como liberarlo?
Gracias.
¡Hola! Una enorme disculpa, no había visto tu mensaje. ¿Todavía estás usando la clase? ¿En qué versión de Delphi?

Saludos.
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117
Responder Con Cita
  #20  
Antiguo 31-08-2017
jars jars is offline
Miembro
 
Registrado: Mar 2004
Posts: 215
Poder: 15
jars Va por buen camino
Hola Al, no hay problema.
En este momento no la estoy usando porque use CreateFileMapping ya que tenía que resolverlo cuanto antes.
De todos modos es una clase muy interesante que me gustaría utilizar.
Desarrollo con Delphi 7
Un abrazo y gracias.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Objetos Perdidos. marcoszorrilla La Taberna 8 04-05-2007 19:50:23
copia de objetos emeceuy OOP 3 11-12-2006 03:59:55
Prioridades de Objetos JerS Varios 2 10-11-2005 13:53:10
Una lista de Objetos en .NET bustio .NET 1 11-10-2004 15:23:08
Objetos jfontane Varios 1 04-07-2003 15:39:04


La franja horaria es GMT +2. Ahora son las 10:37:23.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi