Utilizamos cookies propias y de terceros. [Más información sobre las cookies].
Política de cookies
Proyecto AjpdSoft

· Inicio
· Buscar
· Contactar
· Cookies
· Descargas
· Foros
· Historia
· Nosotros
· Temas
· Top 10
· Trucos
· Tutoriales
· Wiki

Programación: Cómo enviar mensajes entre aplicaciones Delphi mediante el API de Windows
Delphi


Explicamos en este artículo cómo enviar mensajes (cadenas de texto) entre dos aplicaciones diferentes. Utilizamos para ello la función del API de Windows SendMessage con el parámetro especial WM_COPYDATA. Explicamos cómo hacerlo con el lenguaje de programación Borland Delphi 6, aunque es válido para cualquier otra versión incluso para cualquier otro lenguaje de programación. Utilizamos como sistema operativo Microsoft Windows 7.



 

Cómo enviar un mensaje a otra aplicación en el mismo equipo

Vamos a explicar en este artículo cómo enviar un mensaje de texto a otra aplicación del mismo equipo, la aplicación que envía y la que recibe estarán en ejecución. Para ello usaremos la función del API de Windows: SendMessage, declarada en la unidad "Windows.pas" de Delphi con la línea:

function SendMessage; external user32 name 'SendMessageA';

En este artículo explicamos el uso de esta función para el caso del lenguaje de programación Borland Delphi 6, aunque es aplicable a otras versiones de Delphi y, salvando las distancias, a otros lenguajes de programación.

Además de SendMessage, usaremos un parámetro especial para esta función llamado WM_COPYDATA, constante de la unidad "Messages.pas" declarada de la siguiente forma:

{$EXTERNALSYM WM_COPYDATA}
WM_COPYDATA = $004A;

Para el envío y la recepción realizaremos dos aplicaciones diferentes, por un lado la aplicación que enviará el mensaje de texto y por el otro la aplicación que lo recibirá. Ambas aplicaciones deberán estar abiertas al mismo tiempo.

Como se puede observar, en este tipo de comunicación entre aplicaciones es asíncrono y casi inmediato, no se utilizan socket ni nada por el estilo, es una comunicación directa con le único intermediario (lógico) del sistema operativo, que es el que recibe la petición de la aplicación que realiza el envío y la envía a la aplicación que lo recibe.

 

Aplicación que envía el mensaje AjpdSoft Envío mensaje API

En primer lugar vamos a desarrollar la aplicación que enviará el mensaje, para ello crearemos una nueva aplicación desde Delphi, en el formulario de la aplicación añadiremos un TMemo (que llamaremos "txtMensaje") y un TButton (que llamaremos "btEnviar"):

AjpdSoft Cómo enviar mensajes entre aplicaciones diferentes Delphi mediante el API de Windows

A continuación añadiremos las siguientes líneas de código:

1. Hemos de definir una estructura de datos concreta (especificada en la documentación del API de Windows) para enviar los datos del mensaje. Para ello añadiremos el siguiente código antes de "implementation":

...
  var
  formMenuPrincipal: TformMenuPrincipal;

  type
    TCopyDataStruct = packed record
      dwData: DWORD;
      cbData: DWORD;
      lpData: Pointer;
    end;

implementation

{$R *.dfm}

... 

Explicamos cada campo de la estructura TCopyDataStruct:

  • dwData: valor de uso libre, se puede pasar el valor que se desee.
  • cbData: en este campo se debe indicar el tamaño de los datos (en bytes) que se enviarán.
  • lpData: puntero que apuntará a la dirección de memoria donde se encuentra la variable que contiene los datos a enviar.

2. A continuación, en el evento OnClick del botón btEnviar añadiremos el siguiente código, explicamos con comentarios las líneas más importantes:

procedure TformMenuPrincipal.btEnviarClick(Sender: TObject);
var
 estructuraDatos : TCopyDataStruct;
 venRecibe: THandle;
 valorObtenidoRes: integer;
begin
  if txtMensaje.Text <> '' then
  begin
    //Introducimos los datos de la estructura
    estructuraDatos.dwData := 0; //se le puede pasar cualquier valor
    estructuraDatos.cbData := txtMensaje.Width; //tamaño en bytes del mensaje
    estructuraDatos.lpData := PChar(txtMensaje.Text); //puntero al mensaje

    //Comprobamos si está abierta la aplicación que recibirá los datos
    venRecibe := FindWindow(PChar('TFormMenuPrincipal'),
        PChar('AjpdSoft Recibir mensaje API') );
    {Donde:
      TFormMenuPrincipal: será el nombre que le demos al formulario
          de la aplicación que recibirá los datos
      "AjpdSoft Recibir mensaje API": será el titulo (caption) del
          formulario anterior}

    if venRecibe = 0 then
      MessageDlg ('No se ha encontrado abierta la aplicación ' +
          '"AjpdSoft Recibir mensaje API", la aplicación que ' +
          'recibe los datos debe estar abierta.', mtInformation,
          [mbok], 0)
    else
    begin
      //Enviamos el mensaje y obtenemos la respuesta de la
      //aplicación que lo recibe
      valorObtenidoRes := SendMessage(venRecibe, WM_COPYDATA,
          Integer(Handle), Integer(@estructuraDatos));

      //será 1 el valor que pasemos en la aplicación que recibe para indicar
      //que se ha recibido el mensaje correctamente
      if valorObtenidoRes = 1 then
        MessageDlg ('El mensaje enviado ha sido recibido correctamente.',
            mtInformation, [mbok], 0)
      else
        MessageDlg ('Ha habido algún error y el mensaje no ha sido recibido.',
            mtError, [mbok], 0);
    end
  end
  else
    MessageDlg ('Debe introducir el texto a enviar a otra aplicación.',
        mtInformation, [mbok], 0);
end;
 

Aquí podéis ver el código fuente completo de la aplicación AjpdSoft Envío mensaje API.

Si ejecutamos la aplicación en este momento, al no tener aún desarrollada y abierta la aplicación que recibe, mostrará este mensaje:

AjpdSoft Cómo enviar mensajes entre aplicaciones diferentes Delphi mediante el API de Windows

 

 

Aplicación que recibe el mensaje AjpdSoft Recibir mensaje API

Ahora crearemos una nueva aplicación, en este caso sólo necesitaremos un TMemo, que llamaremos "txtMensaje", será aquí donde mostraremos el mensaje recibido. Es importante añadir al Caption del formulario el texto "AjpdSoft Recibir mensaje API" y la propiedad "name" del formulario el valor "FormMenuPrincipal", que son los valores usados para identificar la ventana por parte de la aplicación que envía los datos:

AjpdSoft Aplicación que recibe el mensaje AjpdSoft Recibir mensaje API

A continuación añadiremos las siguientes líneas de código:

1. Declararemos un procedimiento que será el que recoja la petición de la aplicación que envía el mensaje, para ello añadiremos el siguiente código:


...
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TformMenuPrincipal = class(TForm)
    Label1: TLabel;
    txtMensaje: TMemo;
    btSalir: TButton;

    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;

    procedure btSalirClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
...
 

2. En el procedimiento WMCopyData pondremos el siguiente código:

procedure TformMenuPrincipal.WMCopyData(var Msg: TWMCopyData);
begin
  txtMensaje.Text := PChar(Msg.CopyDataStruct.lpData);
  Msg.Result := 1; //Valor de respuesta para indicar que se ha
                  //recibido correctamente la información
  MessageDlg ('Mensaje recibido correctamente de aplicación externa.',
      mtInformation, [mbok], 0);
end; 

Aquí podéis ver el código fuente completo de la aplicación AjpdSoft Recibir mensaje API.

Por supuesto, en el caso de una aplicación real y un uso más lógico a este método, podremos poner el código que queramos en este procedimiento, incluso en función del mensaje que recibimos. Por ejemplo, si recibimos de "PChar(Msg.CopyDataStruct.lpData)" el valor "MOSTRAR", podríamos ejecutar:

formMenuPrincipal.Show;

 

Las dos aplicaciones funcionando: enviar y recibir mensajes

Para realizar una prueba ejecutaremos las dos aplicaciones: envioMensajeAplicacion.exe y recibirMensaje.exe:

AjpdSoft Las dos aplicaciones funcionando: enviar y recibir mensajes

A continuación, en la aplicación aplicación que envía los datos introduciremos un texto cualquiera en "Mensaje a enviar" y pulsaremos "Enviar mensaje":

AjpdSoft Las dos aplicaciones funcionando: enviar y recibir mensajes

La aplicación que recibe el mensaje mostrará este aviso "Mensaje recibido correctamente de aplicación externa", de esta forma sabremos que el código programado funciona correctamente:

AjpdSoft Las dos aplicaciones funcionando: enviar y recibir mensajes

Y la aplicación que recibe escribirá el mensaje en "Mensaje recibido", demostrando así que todo funciona correctamente, a su vez, la aplicación que envía el mensaje muestra el cuadro de diálogo "El mensaje enviado ha sido recibido correctamente":

AjpdSoft Las dos aplicaciones funcionando: enviar y recibir mensajes

 

 

Utilidad del envío de mensajes entre aplicaciones mediante SendMessage y WM_COPYDATA

En el caso de aplicaciones Windows, está claro que puede ser útil para enviar un dato de nuestra aplicación a la calculadora de Windows y así evitar al usuario a introducir el número. O para enviar datos al Bloc de notas o cualquier otra aplicación capaz de recibirlos.

En el caso de dos aplicaciones Delphi desarrolladas por nosotros mismos, puede ser bastante útil en el siguiente escenario de trabajo: imaginemos una aplicación como AjpdSoft Aviso Cambio IP Pública, esta aplicación permite ejecutarse en modo oculto, de forma que una vez abierta en este modo ya no se podrá interactuar con la aplicación salvo que la cerremos con Control + Alt + Sup. Para este tipo de situaciones, podemos programar en la aplicación en cuestión un envío y recepción (en la misma aplicación) de forma que si el usuario intenta abrir la aplicación y ya está abierta, ésta puede recibir un mensaje y realizar cualquier acción, como mostrarse al usuario.

 

Anexo

  • Código fuente completo de AjpdSoft Envío mensaje API:
unit UnidadMenuPrincipal;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons;

type
  TformMenuPrincipal = class(TForm)
    Label1: TLabel;
    txtMensaje: TMemo;
    btEnviar: TBitBtn;
    procedure btEnviarClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  formMenuPrincipal: TformMenuPrincipal;

type
  TCopyDataStruct = packed record
    dwData: DWORD; //De uso libre (se puede pasar el valor que se desee)
    cbData: DWORD; //El tamaño (bytes) de los datos que se enviarán
    lpData: Pointer; //Puntero que apunta al mensaje que se enviará
  end;

implementation

{$R *.dfm}



procedure TformMenuPrincipal.btEnviarClick(Sender: TObject);
var
 estructuraDatos : TCopyDataStruct;
 venRecibe: THandle;
 valorObtenidoRes: integer;
begin
  if txtMensaje.Text <> '' then
  begin
    //Introducimos los datos de la estructura
    estructuraDatos.dwData := 0; //se le puede pasar cualquier valor
    estructuraDatos.cbData := txtMensaje.Width; //tamaño en bytes del mensaje
    estructuraDatos.lpData := PChar(txtMensaje.Text); //puntero al mensaje

    //Comprobamos si está abierta la aplicación que recibirá los datos
    venRecibe := FindWindow(PChar('TFormMenuPrincipal'),
        PChar('AjpdSoft Recibir mensaje API') );
    {Donde:
      TFormMenuPrincipal: será el nombre que le demos al formulario
          de la aplicación que recibirá los datos
      "AjpdSoft Recibir mensaje API": será el titulo (caption) del
          formulario anterior}

    if venRecibe = 0 then
      MessageDlg ('No se ha encontrado abierta la aplicación ' +
          '"AjpdSoft Recibir mensaje API", la aplicación que ' +
          'recibe los datos debe estar abierta.', mtInformation,
          [mbok], 0)
    else
    begin
      //Enviamos el mensaje y obtenemos la respuesta de la
      //aplicación que lo recibe
      valorObtenidoRes := SendMessage(venRecibe, WM_COPYDATA,
          Integer(Handle), Integer(@estructuraDatos));

      //será 1 el valor que pasemos en la aplicación que recibe para indicar
      //que se ha recibido el mensaje correctamente
      if valorObtenidoRes = 1 then
        MessageDlg ('El mensaje enviado ha sido recibido correctamente.',
            mtInformation, [mbok], 0)
      else
        MessageDlg ('Ha habido algún error y el mensaje no ha sido recibido.',
            mtError, [mbok], 0);
    end
  end
  else
    MessageDlg ('Debe introducir el texto a enviar a otra aplicación.',
        mtInformation, [mbok], 0);
end;

end.
 

  • Código fuente completo de AjpdSoft Recibir mensaje API:
unit UnidadMenuPrincipal;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TformMenuPrincipal = class(TForm)
    Label1: TLabel;
    txtMensaje: TMemo;
    btSalir: TButton;

    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;

    procedure btSalirClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  formMenuPrincipal: TformMenuPrincipal;


implementation

{$R *.dfm}

procedure TformMenuPrincipal.WMCopyData(var Msg: TWMCopyData);
begin
  txtMensaje.Text := PChar(Msg.CopyDataStruct.lpData);
  Msg.Result := 1; //Valor de respuesta para indicar que se ha
                  //recibido correctamente la información
  MessageDlg ('Mensaje recibido correctamente de aplicación externa.',
      mtInformation, [mbok], 0);
end;

procedure TformMenuPrincipal.btSalirClick(Sender: TObject);
begin
  close;
end;

end.
 

 

Artículos relacionados

 

 

Créditos

Artículo realizado íntegramente por Alonsojpd miembro fundador del proyecto AjpdSoft.


Anuncios


Enviado el Jueves, 12 agosto a las 17:59:55 por ajpdsoft
Visita nuestro nuevo sitio web con programas y contenidos actualizados: Proyecto A