Реализация IPC vs WM_COPYDATA
Немного теории.
Сообщения WM_COPYDATA дают возможность обмениваться информацией между процессами. Обмен происходит через ядро (kernel). В принимающем процессе выделяется память (space) и удерживается для скопированных ядром данных. Отправитель обязан передать указатель на структуру с данными (COPYDATASTRUCT).
WM_COPYDATA
wParam = (WPARAM) (HWND) hwnd; // дескриптор передающего окна
lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer COPYDATASTRUCT - указатель на структуру с данными
Результат true - если принимающая программа обработала сообщение, false - нет.
Реализация.
1. Создадим структуру, с помощью которой будем обмениваться данными, нам понадобятся:
dwData - этот элемент мы используем, чтобы идентифицировать наши данные, дабы приемник понимал что с ними делать (0-текст 1-бинарные данные).
cbData - элемент будет содержать длину данных
lpData - элемент будет содержать адрес данных (указатель)
Код приложения, которое отправляет данные
размещаем на форме Edit1, Image1 и две кнопки
unit Send2Process;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
// определяем нашу структуру (record)
TCopyDataStruct = packed record
dwData: DWORD; // тип данных
cbData: DWORD; // длина данных
lpData: Pointer; // адрес данных (указатель)
end;
...
{ Public declarations }
// эта процедура будет копировать все, что мы пожелаем
procedure SendCopyData(hTargetWnd: HWND; ACopyDataStruct:TCopyDataStruct);
...
procedure TForm1.SendCopyData(hTargetWnd: HWND; ACopyDataStruct: TCopyDataStruct);
begin
if hTargetWnd <> 0 then
SendMessage(hTargetWnd, WM_COPYDATA, Longint(Handle), Longint(@ACopyDataStruct))
else
ShowMessage('Нет приемника');
end;
Передача текста.
Передаем текст из компонента Edit1
procedure TForm1.Button1Click(Sender: TObject);
var
MyCopyDataStruct: TCopyDataStruct; // наша структура
hRecieverWnd: HWND; // handle приемника
begin
// определяем структуру COPYDATASTRUCT для использования с WM_COPYDATA
with MyCopyDataStruct do
begin
dwData := 0; // 0-текст
cbData := StrLen(PChar(Edit1.Text)) + 1; // длина данных +1 с учетом #0 (terminating)
lpData := PChar(Edit1.Text);
end;
// ищем окно приемника по заголовку 'Message Receiver'
hRecieverWnd := FindWindow(nil,PChar('Message Receiver'));
// Передаем нашу структуру приемнику
SendCopyData(hRecieverWnd, MyCopyDataStruct);
end;
Передаем бинарные данные из потока.
соответственно на форме отправителя помещаем image1 и грузим в нее какую-нибудь картинку
procedure TForm1.Button2Click(Sender: TObject);
var
stream: TMemoryStream; // поток
MyCopyDataStruct: TCopyDataStruct; // наша структура
hRecieverWnd: HWND; // handle приемника
begin
stream := TMemoryStream.Create;
try
image1.Picture.Bitmap.SaveToStream(stream); // пишем картинку в поток
with MyCopyDataStruct do
begin
dwData := 1; // сообщаем, что передаем бинарные данные
cbData := stream.Size; // размер данных
lpData := stream.Memory; // pointer
end;
// Ищем окно по заголовку
hRecieverWnd := FindWindow(nil,PChar('Message Receiver'));
// Отправляем данные
SendCopyData(hRecieverWnd,MyCopyDataStruct);
finally
stream.Free;
end;
end;
Теперь пишем приложение, которое принимает данные.
размещаем на форме Edit1, Image1, Label1, заголовок формы должен быть Message Receiver
структура данных TCopyDataStruct один в один повторяет описание структуры на сервере.
unit ReceiveProcess;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
// структура данных
TCopyDataStruct = packed record
dwData: DWORD; // тип данных
cbData: DWORD; // длина
lpData: Pointer; // адрес
end;
TForm2 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Image1: TImage;
private
// достаем сообщение
procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
{ TForm2 }
procedure TForm2.WMCopyData(var streamg: TWMCopyData);
var
sText: array[0..99] of Char;
stream: TMemoryStream;
begin
case streamg.CopyDataStruct.dwData of
0: // тип данных = 0, значит передали текст
begin
StrLCopy(sText, streamg.CopyDataStruct.lpData, streamg.CopyDataStruct.cbData);
label1.Caption := sText;
end;
1: // тип данных = 1, значит передали бинарные данные
begin
stream := TMemoryStream.Create;
try
with Msg.CopyDataStruct^ do
stream.Write(lpdata^, cbdata); // пишем в поток буфер, который находится по адресу lpdata, длиной cbdata
stream.Position := 0;
image1.Picture.Bitmap.LoadFrostreamtream(stream);
finally
stream.Free;
end;
end;
end;
end;
end.
Ссылки
http://delphi.about.com/od/windowsshellapi/a/wm_copydata.htm - How to Send Information (String, Image, Record) Between Two Applications.
Обзорная Why/What do you Send Between Delphi Applications? там же на delphi.about.com
Немного теории.
Сообщения WM_COPYDATA дают возможность обмениваться информацией между процессами. Обмен происходит через ядро (kernel). В принимающем процессе выделяется память (space) и удерживается для скопированных ядром данных. Отправитель обязан передать указатель на структуру с данными (COPYDATASTRUCT).
WM_COPYDATA
wParam = (WPARAM) (HWND) hwnd; // дескриптор передающего окна
lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer COPYDATASTRUCT - указатель на структуру с данными
Результат true - если принимающая программа обработала сообщение, false - нет.
Реализация.
1. Создадим структуру, с помощью которой будем обмениваться данными, нам понадобятся:
dwData - этот элемент мы используем, чтобы идентифицировать наши данные, дабы приемник понимал что с ними делать (0-текст 1-бинарные данные).
cbData - элемент будет содержать длину данных
lpData - элемент будет содержать адрес данных (указатель)
Код приложения, которое отправляет данные
размещаем на форме Edit1, Image1 и две кнопки
unit Send2Process;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
// определяем нашу структуру (record)
TCopyDataStruct = packed record
dwData: DWORD; // тип данных
cbData: DWORD; // длина данных
lpData: Pointer; // адрес данных (указатель)
end;
...
{ Public declarations }
// эта процедура будет копировать все, что мы пожелаем
procedure SendCopyData(hTargetWnd: HWND; ACopyDataStruct:TCopyDataStruct);
...
procedure TForm1.SendCopyData(hTargetWnd: HWND; ACopyDataStruct: TCopyDataStruct);
begin
if hTargetWnd <> 0 then
SendMessage(hTargetWnd, WM_COPYDATA, Longint(Handle), Longint(@ACopyDataStruct))
else
ShowMessage('Нет приемника');
end;
Передача текста.
Передаем текст из компонента Edit1
procedure TForm1.Button1Click(Sender: TObject);
var
MyCopyDataStruct: TCopyDataStruct; // наша структура
hRecieverWnd: HWND; // handle приемника
begin
// определяем структуру COPYDATASTRUCT для использования с WM_COPYDATA
with MyCopyDataStruct do
begin
dwData := 0; // 0-текст
cbData := StrLen(PChar(Edit1.Text)) + 1; // длина данных +1 с учетом #0 (terminating)
lpData := PChar(Edit1.Text);
end;
// ищем окно приемника по заголовку 'Message Receiver'
hRecieverWnd := FindWindow(nil,PChar('Message Receiver'));
// Передаем нашу структуру приемнику
SendCopyData(hRecieverWnd, MyCopyDataStruct);
end;
Передаем бинарные данные из потока.
соответственно на форме отправителя помещаем image1 и грузим в нее какую-нибудь картинку
procedure TForm1.Button2Click(Sender: TObject);
var
stream: TMemoryStream; // поток
MyCopyDataStruct: TCopyDataStruct; // наша структура
hRecieverWnd: HWND; // handle приемника
begin
stream := TMemoryStream.Create;
try
image1.Picture.Bitmap.SaveToStream(stream); // пишем картинку в поток
with MyCopyDataStruct do
begin
dwData := 1; // сообщаем, что передаем бинарные данные
cbData := stream.Size; // размер данных
lpData := stream.Memory; // pointer
end;
// Ищем окно по заголовку
hRecieverWnd := FindWindow(nil,PChar('Message Receiver'));
// Отправляем данные
SendCopyData(hRecieverWnd,MyCopyDataStruct);
finally
stream.Free;
end;
end;
Теперь пишем приложение, которое принимает данные.
размещаем на форме Edit1, Image1, Label1, заголовок формы должен быть Message Receiver
структура данных TCopyDataStruct один в один повторяет описание структуры на сервере.
unit ReceiveProcess;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
// структура данных
TCopyDataStruct = packed record
dwData: DWORD; // тип данных
cbData: DWORD; // длина
lpData: Pointer; // адрес
end;
TForm2 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Image1: TImage;
private
// достаем сообщение
procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
{ TForm2 }
procedure TForm2.WMCopyData(var streamg: TWMCopyData);
var
sText: array[0..99] of Char;
stream: TMemoryStream;
begin
case streamg.CopyDataStruct.dwData of
0: // тип данных = 0, значит передали текст
begin
StrLCopy(sText, streamg.CopyDataStruct.lpData, streamg.CopyDataStruct.cbData);
label1.Caption := sText;
end;
1: // тип данных = 1, значит передали бинарные данные
begin
stream := TMemoryStream.Create;
try
with Msg.CopyDataStruct^ do
stream.Write(lpdata^, cbdata); // пишем в поток буфер, который находится по адресу lpdata, длиной cbdata
stream.Position := 0;
image1.Picture.Bitmap.LoadFrostreamtream(stream);
finally
stream.Free;
end;
end;
end;
end;
end.
Ссылки
http://delphi.about.com/od/windowsshellapi/a/wm_copydata.htm - How to Send Information (String, Image, Record) Between Two Applications.
Обзорная Why/What do you Send Between Delphi Applications? там же на delphi.about.com