Share data between two Delphi applications  

Send By: Radikal (Q3 Team)
Web : http://www.q3.nu
Email: radikal@q3.nu
Date: 28/01/00

Tip accessed 3950 times

 


There are several ways to make it.
In this tip, we will use a memory file to be able to share an memory area, and to be able to this wayto send data from an application to the other.

We will create two applications, one for write the data and other, that receives them.
In short, we will make that the text of a TEdit is seen in the Label of the other application.


Application that will write the data



  • Make a new application
  • Put a TEdit in the form (Edit1)
  • Replace the source of the form's unit for this:

     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:=666;
        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.
    




    Application that will read the data



  • Make a new application
  • Put a TTimer (Timer1) and a TLabel (Label1) in your form
  • Deactivate Timer1 (property Enabled=FALSE);
  • Replace the source of the form's unit for this:

     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.
    



    Now it compiles and run the first application and it compiles and run the second.
    What you write in the Edit of an application will come out in the Label of the other.

    The operation is the following one:

    In the first application, let us believe a memory file by means of


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



    that that makes it is to allow us to share an memory area.
    To facilitate us the access to this memory area, we will manage it by means of a structure that there are us made:



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



    Here you should be careful... the structure should have a defined size, this means... that cannot make a structure of this type:



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



    because the length of this structure would depend on the length of the string contained in ' Cadena'.
    Once created the file, we address a pointer to the area of memory to which the file points, to be able to to write the data in our structure:


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



    In such a way that all that we write through our structure, will be written in the memory area of the file, and it will be accessible for other applications that use the same file:


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





    Now see how to read these data from another Delphi application:
    In this case, instead of creating the file, we will open it for reading.


       {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');
    



    and we generate an error if we have not been able to open it (for example because it has not been created by the other application)

    Once the file has been open, we activate the Timer1, so that each x time refreshes the Label1 with the string received from the other application through the memory file:


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



    Ah, lastly, to say that we should close the view of the memory file so much as the own file memory when we finish using them. For example, in the OnDestroy event of the form:


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





    To finish... some ideas to improve this tip and to continue playing with memory files (I have already gotten tired...):

  • To make that the application that writes the data, report to the other that has written new data by means of a personalized message, instead of reading them each x time with a timer in the receiver application.

    If you cheer up to make something of this... send me an example, we will learn this way all...


    Well, it seems that somebody has cheered up :)

    Here a new example is, based on the previous one but that it uses an own message to warn to the other application that there are new data:

    Send By: Arturo García (sArthur7@teleline.es)


    Application that will write the data




     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.
    




    Application that will read the data




     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.