API Delphi

Question:
How can I use the WM_COPYDATA message to pass information between
16-bit and 32-bit applications?
Answer:
The following example shows how to use the WM_COPYDATA message to
send a record containing data between a 16-bit and 32-bit application.
This method can also be used to call 16-bit or 32-bit dll from a
16-bit or 32-bit application (known as thunking). Thunking can be
accomplished by creating an invisible window to respond to the
WM_COPYDATA message, and call the dll in your behalf.
Compile the following unit source code under both 16-bit and 32-bit
versions of Delphi. Use separate directories for the two projects.
Each project will require a form, a button, and a memo component on
it's form.
To use the WM_COPYDATA message, you must send the address of a
TCopyDataStruct to the receiving window. The dwData parameter of the
TCopyDataStruc is a user defined parameter that allows you to store
any 32 bit value you wish, for additional information. The cbData
member of the TCopyDataStruc contains the size of the data pointed to
by the lpData member of the TCopyDataStruc. The lpData parameter of
the TCopyDataStruct can point to any data structure you wish.
Note that any pointers contained in the structure you send will not be
valid from the receiving application since windows has no way to
convert them. Note that the data that is passed to the receiving
application is only valid during the call. If the receiving
application needs to retain the information passed, it should make a
copy of the data that is local to the receiving application. The
receiving application should not modify the data that is passed during
the call. If modifications are necessary, the receiving application
should make a local copy of the data, and send a WM_COPYDATA message
back to the sending application using the modified copy.
It's worth noting that the WM_COPYDATA message will work going to and
from any combination of 16/32 bit applications. Finally, be aware that
the call to SendMessage will not return untill the message is
processed. Also be aware that you should never use PostMessage() with
the WM_COPYDATA message.
unit Unit1;
interface
{$IFDEF WIN32}
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
{$ELSE}
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
{$ENDIF}
const WM_COPYDATA = $004A;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure WMCopyData(var m : TMessage); message WM_COPYDATA;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
type
PCopyDataStruct = ^TCopyDataStruct;
TCopyDataStruct = record
dwData: LongInt;
cbData: LongInt;
lpData: Pointer;
end;
type
PRecToPass = ^TRecToPass;
TRecToPass = packed record
s : string[255];
i : integer;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
{$IFDEF WIN32}
Form1.Caption := 'My 32-Bit App'
{$ELSE}
Form1.Caption := 'My 16-Bit App'
{$ENDIF}
end;
procedure TForm1.WMCopyData(var m : TMessage);
begin
Memo1.Lines.Add('Sending Window Handle := ' +
IntToStr(m.WParam));
Memo1.Lines.Add('Data Size := ' +
IntToStr(PCopyDataStruct(m.LParam)^.cbData));
Memo1.Lines.Add('User Defined Data Param := ' +
IntToStr(PCopyDataStruct(m.LParam)^.dwData));
Memo1.Lines.Add('TRecToPass.s := ' +
PRecToPass(PCopyDataStruct(m.LParam)^.lpData)^.s);
Memo1.Lines.Add('TRecToPass.i := ' +
IntToStr(
PRecToPass(PCopyDataStruct(m.LParam)^.lpData)^.i));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
h : THandle;
cd : TCopyDataStruct;
rec : TRecToPass;
begin
{$IFDEF WIN32}
h := FindWindow(nil, 'My 16-Bit App');
rec.s := 'Hello World From: My 32-Bit App';
rec.i := 32;
cd.dwData := 3232;
{$ELSE}
h := FindWindow(nil, 'My 32-Bit App');
rec.s := 'Hello World From: My 16-Bit App';
rec.i := 16;
cd.dwData := 1616;
{$ENDIF}
cd.cbData := sizeof(rec);
cd.lpData := @rec;
if h <> 0 then
SendMessage(h, WM_COPYDATA, Form1.Handle, LongInt(@cd));
end;
end.