Delphi Programming

  1. Home
  2. Computing & Technology
  3. Delphi Programming

How to Send Information (String, Image, Record) Between Two Applications

By Zarko Gajic, About.com

There are many situation when you need to allow for two applications to communicate. If you do not want to mess with TCP and sockets communication (because both applications are running on the same machine), you can *simply* send (and properly receive) a special Windows message: WM_COPYDATA.

Since handling Windows messages in Delphi is simple, issuing a SendMessage API call along with the WM_CopyData filled with the data to be sent is quite straight forward.

WM_CopyData and TCopyDataStruct

The WM_COPYDATA message enables you to send data from one application to another. The receiving application receives the data in a TCopyDataStruct record. The TCopyDataStruct is defined in the Windows.pas unit and wraps the COPYDATASTRUCT structure that contains the data to be passed.

Here's the declaration and the description of the TCopyDataStruct record:

type
   TCopyDataStruct = packed record
    dwData: DWORD; //up to 32 bits of data to be passed to the receiving application
    cbData: DWORD; //the size, in bytes, of the data pointed to by the lpData member
    lpData: Pointer; //Points to data to be passed to the receiving application. This member can be nil.
   end;

Send a String over WM_CopyData

For a "Sender" application to send data to "Receiver" the CopyDataStruct must be filled and passed using the SendMessage function. Here's how to send a string value over WM_CopyData:
procedure TSenderMainForm.SendString() ;
var
   stringToSend : string;
   copyDataStruct : TCopyDataStruct;
begin
   stringToSend := 'About Delphi Programming';

   copyDataStruct.dwData := 0; //use it to identify the message contents
   copyDataStruct.cbData := 1 + Length(stringToSend) ;
   copyDataStruct.lpData := PChar(stringToSend) ;

   SendData(copyDataStruct) ;
end;
The SendData custom function locates the receiver using the FindWindow API call:
procedure TSenderMainForm.SendData(const copyDataStruct: TCopyDataStruct) ;
var
  receiverHandle : THandle;
  res : integer;
begin
  receiverHandle := FindWindow(PChar('TReceiverMainForm'),PChar('ReceiverMainForm')) ;
  if receiverHandle = 0 then
  begin
    ShowMessage('CopyData Receiver NOT found!') ;
    Exit;
  end;

  res := SendMessage(receiverHandle, WM_COPYDATA, Integer(Handle), Integer(@copyDataStruct)) ;
end;
In the code above, the "Receiver" application was found using the FindWindow API call by passing the class name of the main form ("TReceiverMainForm") and the caption of the window ("ReceiverMainForm").

Note: The SendMessage returns an integer value assigned by the code that handled the WM_CopyData message.

Handling WM_CopyData - Receiving a String

The "Receiver" application handles the WM_CopyData mesage as in:
type
  TReceiverMainForm = class(TForm)
  private
   procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;
...
implementation
...
procedure TReceiverMainForm.WMCopyData(var Msg: TWMCopyData) ;
var
  s : string;
begin
  s := PChar(Msg.CopyDataStruct.lpData) ;

  //Send something back
  msg.Result := 2006;
end;
The TWMCopyData record is declared as:
TWMCopyData = packed record
Msg: Cardinal;
 From: HWND;//Handle of the Window that passed the data
 CopyDataStruct: PCopyDataStruct; //data passed
 Result: Longint;//Use it to send a value back to the "Sender"
end;

Sending String, Custom Record or an Image?

The accompanying source code demonstrates how to send a string, record (complex data type) and even graphics (bitmap) to another application.

If you cannot wait the download, here's how to send a TBitmap graphics:

procedure TSenderMainForm.SendImage() ;
var
   ms : TMemoryStream;
   bmp : TBitmap;
   copyDataStruct : TCopyDataStruct;
begin
   ms := TMemoryStream.Create;
   try
     bmp := self.GetFormImage;
     try
       bmp.SaveToStream(ms) ;
     finally
       bmp.Free;
     end;

     copyDataStruct.dwData := Integer(cdtImage) ; // identify the data
     copyDataStruct.cbData := ms.Size;
     copyDataStruct.lpData := ms.Memory;

     SendData(copyDataStruct) ;
   finally
     ms.Free;
   end;
end;
And how to receive it:
procedure TReceiverMainForm.HandleCopyDataImage(
   copyDataStruct: PCopyDataStruct) ;
var
   ms: TMemoryStream;
begin
   ms := TMemoryStream.Create;
   try
     ms.Write(copyDataStruct.lpData^, copyDataStruct.cbData) ;
     ms.Position := 0;
     receivedImage.Picture.Bitmap.LoadFromStream(ms) ;
   finally
     ms.Free;
   end;
end;

Downloadwm_copydata source code example.

Readers Respond: Real World Examples Needed: Why/What do you Send Between Delphi Applications?

Zarko Gajic
Guide since 1998

Zarko Gajic
Delphi Programming Guide

Explore Delphi Programming

About.com Special Features

Delphi Programming

  1. Home
  2. Computing & Technology
  3. Delphi Programming
  4. Advanced Delphi Techniques
  5. How to Send Information (String, Image, Record) Between Two Delphi Applications Using WM_COPYDATA

©2009 About.com, a part of The New York Times Company.

All rights reserved.