Compartir datos por medio de un fichero en memoria en Delphi

Hay varias maneras de hacerlo. 
En este truco, usaremos un fichero de memoria para poder compartir una zona de memoria, y poder así enviar datos de una aplicación a la otra. 

Crearemos dos aplicaciones, una la que escriba los datos y otra, la que los reciba. 
En concreto, haremos que el texto de un TEdit se vea el un Label de la otra aplicación.


Aplicacion que escribe los datos:




  • Crea una nueva aplicacion 
  • Pon un TEdit en la form (Edit1) 
  • Cambia el código de la unit de la form por éste: 

     unit Unit1;
    
     interface
    
     uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       StdCtrls;
    
     type
       TForm1 = class(TForm)
         Edit1: TEdit;
         procedure FormCreate(Sender: TObject);
         procedure Edit1Change(Sender: TObject);
         procedure FormDestroy(Sender: TObject);
       private
         { Private declarations }
       public
         { Public declarations }
       end;
    
     type
      TCompartido = record
        Numero: Integer;
        Cadena: String[20];
      end;
      PCompartido   =^TCompartido;
    
     var
       Form1      : TForm1;
       Compartido : PCompartido;
       FicheroM   : THandle;
     implementation
    
     {$R *.DFM}
    
     procedure TForm1.FormCreate(Sender: TObject);
     begin
       Edit1.MaxLength:=20;
       {Creamos el fichero de memoria}
       FicheroM:=CreateFileMapping( $FFFFFFFF,
                                   nil,
                                   PAGE_READWRITE,
                                   0,
                                   SizeOf(TCompartido),
                                   'MiFichero');
        {Si no se creó el fichero, lo llenamos de ceros}
        if FicheroM=0 then
          raise Exception.Create( 'Error al crear el fichero'+
                                  '/Error while create file');
    
        {Direccionamos nuestra estructura al fichero de memoria}
        Compartido:=MapViewOfFile(FicheroM,FILE_MAP_WRITE,0,0,0);
    
        {Escribimos datos en el fichero de memoria}
        Compartido^.Numero:=732;
        Compartido^.Cadena:=Edit1.text;
     end;
    
     procedure TForm1.Edit1Change(Sender: TObject);
     begin
       Compartido^.Cadena:=Edit1.Text;
     end;
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       {Cerramos la vista del fichero}
       UnmapViewOfFile(Compartido);
       {Cerramos el fichero}
       CloseHandle(FicheroM);
     end;
    
     end.
    




    Aplicacion que leera los datos:


  • Crea una nueva aplicacion 
  • Pon un TTimer (Timer1) y un TLabel (Label1) en tu form 
  • Desactiva el Timer1 (propiedad Enabled=FALSE); 
  • Cambia el código de la unit de la form por este: 

     unit Unit1;
    
     interface
    
     uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       ExtCtrls, StdCtrls;
    
     type
       TForm1 = class(TForm)
         Label1: TLabel;
         Timer1: TTimer;
         procedure FormCreate(Sender: TObject);
         procedure Timer1Timer(Sender: TObject);
         procedure FormDestroy(Sender: TObject);
       private
         { Private declarations }
       public
         { Public declarations }
       end;
    
     type
      TCompartido = record
        Numero: Integer;
        Cadena: String[20];
      end;
      PCompartido   =^TCompartido;
    
     var
       Form1       : TForm1;
       Compartido  : PCompartido;
       FicheroM    : THandle;
    
     implementation
    
     {$R *.DFM}
    
     procedure TForm1.FormCreate(Sender: TObject);
     begin
       {Miramos si existe el fichero}
       FicheroM:=OpenFileMapping(FILE_MAP_READ,False,'MiFichero');
       {Si no existe, Error}
       if FicheroM=0 then
         raise Exception.Create('Error');
    
        Compartido:=MapViewOfFile(FicheroM,FILE_MAP_READ,0,0,0);
        Timer1.Enabled:=TRUE;
     end;
    
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       UnmapViewOfFile(Compartido);
       CloseHandle(FicheroM);
     end;
    
     procedure TForm1.Timer1Timer(Sender: TObject);
     begin
       Label1.Caption:=Compartido^.Cadena;
     end;
    
    
     end.
    



    Ahora compila y arranca la primera aplicacion y compila y arranca la segunda.
    Lo que escribas en el Edit de una aplicacion saldrá en el Label de la otra.

    El funcionamiento es el siguiente:

    En la primera aplicación, creamos un fichero de memoria mediante: 



       {Creamos el fichero de memoria}
       {Create the memory file}
       FicheroM:=CreateFileMapping( $FFFFFFFF,
                                   nil,
                                   PAGE_READWRITE,
                                   0,
                                   SizeOf(TCompartido),
                                   'MiFichero');
    



    que lo que hace es permitirnos compartir una zona de memoria.
    Para facilitarnos el acceso a esta zona de memoria, la manejaremos mediante una estructura que nos hemos creado a tal efecto: 




     type
      TCompartido = record
        Numero: Integer;
        Cadena: String[20];
      end;
      PCompartido   =^TCompartido;
    



    Aqui debes tener cuidado... la estructura debe tener un tamaño definido, esto quiere decir... que no podrías hacer una estructura de este tipo:



     type
      TCompartido = record
        Numero: Integer;
        Cadena: String;
      end;
      PCompartido   =^TCompartido;
    



    ya que la longitud de esta estructura dependería de la longitud de la string contenida en 'Cadena'.
    Una vez creado el fichero, direccionamos un puntero a la zona de memoria a la que apunta el fichero, para poder escribir los datos en nuestra estructura: 



     {Direccionamos nuestra estructura al fichero de memoria}
     {Addressing the memory zone with our structure}
     Compartido:=MapViewOfFile(FicheroM,FILE_MAP_WRITE,0,0,0);
    



    De tal manera que todo lo que escribamos a través de nuestra estructura, se escribirá en la zona de memoria del fichero de memoria, y será accesible para otras aplicaciones que mapeen el mismo fichero: 


     {Escribimos datos en el fichero de memoria}
     {Wrire data in the memory file}
     Compartido^.Numero:=732;
     Compartido^.Cadena:=Edit1.text;
    





    Ahora veamos cómo leer estos datos desde otra aplicación Delphi:
    En este caso, en lugar de crear el fichero, lo abriremos para lectura. 



       {Miramos si existe el fichero}
       {Look for the file}
       FicheroM:=OpenFileMapping(FILE_MAP_READ,False,'MiFichero');
       {Si no existe, Error}
       {If don't exists... error}
       if FicheroM=0 then
         raise Exception.Create('Error');
    



    y generamos un error si no hemos sido capaces de abrirlo (por ejemplo porque no haya sido creado por la otra aplicación)

    Una vez que el fichero ha sido abierto, activamos el Timer1, para que cada x tiempo refresque el Label1 con la cadena recibida desde la otra aplicación a través del fichero de memoria: 



     procedure TForm1.Timer1Timer(Sender: TObject);
     begin
       Label1.Caption:=Compartido^.Cadena;
     end;
    



    Ah, por último, decir que debemos cerrar tanto la vista del fichero de memoria como el propio fichero de memoria cuando terminemos de usarlos. Por ejemplo, en el evento OnDestroy de la form: 


     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       UnmapViewOfFile(Compartido);
       CloseHandle(FicheroM);
     end;
    








    Aqui está un nuevo ejemplo, basado en el anterior pero que utiliza un mensaje propio para avisar a la otra aplicación de que hay nuevos datos:

    Enviado por: Arturo García (sArthur7@teleline.es) 


    Aplicacion que escribe los datos 




     unit Trans;
    
     interface
    
     uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       StdCtrls;
    
     CONST
       WM_TRANSFER = WM_USER + 1;  // Definimos un mensaje
    
     type
      PCompartido =^TCompartido;
      TCompartido = record
        Manejador1: Cardinal;
        Manejador2: Cardinal;
        Numero    : Integer;
        Cadena    : String[20];
      end;
    
     (*  -------------------------------------- *)
    
     type
       TForm1 = class(TForm)
         Edit1: TEdit;
         procedure FormCreate(Sender: TObject);
         procedure Edit1Change(Sender: TObject);
         procedure FormDestroy(Sender: TObject);
         procedure Edit1KeyDown(Sender: TObject; var Key: Word;
           Shift: TShiftState);
       private
         Compartido : PCompartido;
         FicheroM   : THandle;
       public
         { Public declarations }
       end;
    
     var
       Form1: TForm1;
    
     implementation
    
     {$R *.DFM}
    
     procedure TForm1.FormCreate(Sender: TObject);
     begin
        Edit1.MaxLength:=20;
       {Creamos el fichero de memoria}
       FicheroM:=CreateFileMapping( $FFFFFFFF,nil,PAGE_READWRITE,0,
                                   SizeOf(TCompartido),'MiFichero');
        {Si no se creó el fichero, lo llenamos de ceros}
        if FicheroM=0 then
          raise Exception.Create( 'Error al crear el fichero'+
                                  '/Error while create file');
    
        {Direccionamos nuestra estructura al fichero de memoria}
        Compartido:=MapViewOfFile(FicheroM,FILE_MAP_WRITE,0,0,0);
    
        {Escribimos datos en el fichero de memoria}
        Compartido^.Manejador1:=Handle;
        Compartido^.Numero:=777;
        Compartido^.Cadena:=Edit1.text;
     end;
    
     procedure TForm1.Edit1Change(Sender: TObject);
     begin
       Compartido^.Cadena:=Edit1.Text;
     end;
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
      {Cerramos la vista del fichero}
       UnmapViewOfFile(Compartido);
       {Cerramos el fichero}
       CloseHandle(FicheroM);
     end;
    
     procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
       Shift: TShiftState);
     begin
      if key = 13 then Begin
         if compartido^.Manejador2 <> 0 then
          PostMessage(Compartido^.Manejador2, WM_TRANSFER,0, 0);
      end;
     end;
    
     end.
    




    Aplicacion que leera los datos 




     unit Recep;
    
     interface
    
     uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       StdCtrls;
    
     const
       WM_TRANSFER = WM_USER + 1;
    
     type
      PCompartido =^TCompartido;
      TCompartido = record
        Manejador1: Cardinal;
        Manejador2: Cardinal;
        Numero    : Integer;
        Cadena    : String[20];
      end;
    
     type
       TForm1 = class(TForm)
         Label1: TLabel;
         procedure FormCreate(Sender: TObject);
         procedure FormDestroy(Sender: TObject);
       private
         Compartido : PCompartido;
         FicheroM   : THandle;
         procedure Reciviendo(var Msg: TMessage); message WM_TRANSFER;
    
       public
         { Public declarations }
       end;
    
     var
       Form1: TForm1;
    
     implementation
    
     {$R *.DFM}
    
     procedure Tform1.Reciviendo(var Msg: TMessage);
     begin
      label1.Caption:=compartido^.Cadena;
     end;
    
     procedure TForm1.FormCreate(Sender: TObject);
     begin
       {Miramos si existe el fichero}
       FicheroM:=OpenFileMapping(FILE_MAP_READ,False,'MiFichero');
       {Si no existe, Error}
       if FicheroM=0 then
         raise Exception.Create('Error');
         Compartido:=MapViewOfFile(FicheroM,FILE_MAP_READ,0,0,0);
         compartido^.Manejador2:=Handle;
     end;
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       UnmapViewOfFile(Compartido);
       CloseHandle(FicheroM);
     end;
    
     end.
     
  • Ref: http://www.trucomania.org/trucomania/truco.cgi?381&esp



    También te puede interesar:

    App para mostrar moléculas en 3D


    No hay comentarios:

    Publicar un comentario