Compartir datos entre dos aplicaciones propias

3228 vistas

De lo que se trata es de dar una idea de cómo compartir información entre dos aplicaciones realizadas por nosotros.

Hay muchas maneras de hacerlo, pero vamos a ver cómo hacerlo usando un fichero de memoria  para poder compartir una zona de memoria y poder asà enviar la información de una aplicación a otra.

El funcionamiento será el siguiente:

Aplicación que escribirá en la memoria

Ésta será la encargada de crear el fichero de memoria mediante la API CreateFileMapping, la cual se encarga de reservar el espacio de memoria necesario. Para ello, también se definirá una estructura de tamaño fijo (!!atención a la utilización de strings, éstos tienen que tener tamaño fijo!!)

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 mediante la API MapViewOfFile:

De esta manera, cualquier cosa que se escriba en la estructura se escribirá en la zona de memoria del fichero de memoria, y será accesible para otras aplicaciones que
mapeen el mismo fichero:

Además, se enviará un mensaje de Windows para advertir a la otra aplicación que se ha cambiado la información compartida.

Por otra parte, no podemos alvidarnos de cerrar tanto la vista del fichero de memoria como el propio fichero de memoria cuando ya no la necesitemos (por ejemplo en el OnDestroy) mediante la API UnmapViewOfFile y CloseHandle.

Asà quedarÃa el programa de escritura


delphi
  1. unit Trans;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. const
  10.   WM_TRANSFER = WM_USER + 1;  // Definimos un mensaje
  11.  
  12. type
  13. PCompartido = ^TCompartido;
  14. TCompartido = record
  15.   Manejador1: Cardinal;
  16.   Manejador2: Cardinal;
  17.   Cadena: String[20];
  18. end;
  19.  
  20. type
  21.   TForm1 = class(TForm)
  22.     Edit1: TEdit;
  23.     procedure FormCreate(Sender: TObject);
  24.     procedure Edit1Change(Sender: TObject);
  25.     procedure FormDestroy(Sender: TObject);
  26.     procedure Edit1KeyDown(Sender: TObject; var Key: Word;
  27.       Shift: TShiftState);
  28.   private
  29.     Compartido: PCompartido;
  30.     FicheroM: THandle;
  31.   public
  32.   end;
  33.  
  34. var
  35.   Form1: TForm1;
  36.  
  37. implementation
  38.  
  39. {$R *.DFM}
  40.  
  41. procedure TForm1.FormCreate(Sender: TObject);
  42. begin
  43.   Edit1.MaxLength := 20;
  44.   { Creamos el fichero de memoria }
  45.   FicheroM := CreateFileMapping( $FFFFFFFF, nil, PAGE_READWRITE, 0,
  46.                               SizeOf(TCompartido), 'MiFichero');
  47.   { Si no se creó el fichero, lanzamos excepción }
  48.   if FicheroM = 0 then
  49.     raise Exception.Create( 'Error al crear el fichero');
  50.  
  51.   { Direccionamos nuestra estructura al fichero de memoria }
  52.   Compartido := MapViewOfFile(FicheroM,FILE_MAP_WRITE, 0, 0, 0);
  53.  
  54.   { Inicializamos estructura }
  55.   Compartido^.Manejador1 := Handle;
  56. end;
  57.  
  58. procedure TForm1.Edit1Change(Sender: TObject);
  59. begin
  60.   // cada vez que haya un cambio en el TEdit, escribimos en el fichero de memoria
  61.   Compartido^.Cadena := Edit1.Text;
  62. end;
  63.  
  64. procedure TForm1.FormDestroy(Sender: TObject);
  65. begin
  66.   { Cierre de la vista del fichero }
  67.   UnmapViewOfFile(Compartido);
  68.   { Cierre del fichero }
  69.   CloseHandle(FicheroM);
  70. end;
  71.  
  72. procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
  73.   Shift: TShiftState);
  74. begin
  75.   // al pulsar ENTER, lanzamos mensaje de Windows si se ha especificado la
  76.   //  aplicación de lectura (Manejador2 de la estructura)
  77.   if key = 13 then
  78.     if compartido^.Manejador2 <> 0 then
  79.       PostMessage(Compartido^.Manejador2, WM_TRANSFER,0, 0);
  80. end;
  81.  
  82. end.



Aplicación que leerá los datos

A diferencia de la aplicación "escritora", ésta no creará el fichero de memoria, sino que lo abrirá para lectura mediante la API OpenFileMapping controlando el hecho de no poder abrirlo debido a que la aplicación "escritora" no lo ha creado aun (o no ha sido capaz).

Tendremos que capturar el mensaje de Windows enviado por la aplicación "escritora" y leer la información enviada.

Como en la otra aplicación, no podemos alvidarnos de cerrar tanto la vista del fichero de memoria como el propio fichero de memoria cuando ya no la necesitemos (por ejemplo en el OnDestroy) mediante la API UnmapViewOfFile y CloseHandle.

Asà quedarÃa el programa de lectura


delphi
  1. unit Recep;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. const
  10.   WM_TRANSFER = WM_USER + 1;
  11.  
  12. type
  13. PCompartido = ^TCompartido;
  14. TCompartido = record
  15.   Manejador1: Cardinal;
  16.   Manejador2: Cardinal;
  17.   Cadena: String[20];
  18. end;
  19.  
  20. type
  21.   TForm1 = class(TForm)
  22.     Label1: TLabel;
  23.     procedure FormCreate(Sender: TObject);
  24.     procedure FormDestroy(Sender: TObject);
  25.   private
  26.     Compartido: PCompartido;
  27.     FicheroM: THandle;
  28.     procedure Reciviendo(var Msg: TMessage); message WM_TRANSFER;
  29.   public
  30.   end;
  31.  
  32. var
  33.   Form1: TForm1;
  34.  
  35. implementation
  36.  
  37. {$R *.DFM}
  38.  
  39. procedure Tform1.Reciviendo(var Msg: TMessage);
  40. begin
  41.   label1.Caption := compartido^.Cadena;
  42. end;
  43.  
  44. procedure TForm1.FormCreate(Sender: TObject);
  45. begin
  46.   { Miramos si existe el fichero }
  47.   FicheroM := OpenFileMapping(FILE_MAP_READ, False, 'MiFichero');
  48.   { Si no existe, lanzamos error }
  49.   if FicheroM = 0 then
  50.     raise Exception.Create('Error');
  51.  
  52.   // si existe direccionamos puntero y lo inicializamos
  53.   Compartido := MapViewOfFile(FicheroM, FILE_MAP_READ, 0, 0, 0);
  54.   compartido^.Manejador2 := Handle;
  55. end;
  56.  
  57. procedure TForm1.FormDestroy(Sender: TObject);
  58. begin
  59.   { Cerramos la vista del fichero }
  60.   UnmapViewOfFile(Compartido);
  61.   { Cerramos el fichero }
  62.   CloseHandle(FicheroM);
  63. end;
  64.  
  65. end.