Compartir datos por medio de un fichero en memoria con 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 será la que escriba los datos y otra será la que los reciba. 
En concreto, haremos que el texto de un TEdit se vea en el Label de otra aplicación.





Aplicación 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.








    Aplicación que leerá 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, creamos 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) 



    Aplicación 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.








    Aplicación que leerá 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










    No hay comentarios:

    Publicar un comentario

    Simulación del movimiento de los electrones en un campo electrico

    Espectacular simulación realizada con OpenGL del movimiento de los electrones cuando atraviesan un campo eléctrico. Como muestra la image...