При работе с несколькими процессами в Delphi иногда возникает потребность передавать данные между ними. Одним из способов достижения этой цели является использование функции SendMessage, которая отправляет сообщение в оконный сообщённый порт (window message) другого процесса. Тем не менее, при передаче данных между процессами с помощью SendMessage и пользовательского сообщения WM_MyMessage могут возникнуть трудности.
Проблема:
При попытке отправить данные между двумя процессами с помощью SendMessage и WM_MyMessage может возникнуть проблема, когда передача данных работает только в пределах одного процесса. Это происходит потому, что адреса только имеют смысл в рамках одного процесса, и адрес, созданный в одном процессе, является мусором в целевом процессе.
Пример:
Ниже представлен пример, иллюстрирующий описанную проблему:
MainApps.pas:
Type
PMyrec = ^TMyrec;
TMyrec = Record
name : string;
add : string;
age : integer;
end;
procedure TForm1.ButtonSendClick(Sender: TObject);
var
aData: PMyrec;
begin
new(aData);
aData^.Name := 'MyName';
aData^.Add := 'My Address';
aData^.Age := 18;
SendMessage(FindWindow('SubApps'), WM_MyMessage, 0, Integer(@aData));
end;
SubApps.pas:
Type
PMyrec = ^TMyrec;
TMyrec = Record
name : string;
add : string;
age : integer;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnCaptureMessage;
end;
function TForm1.OnCaptureMessage(var Msg: TMessage; var Handled: Boolean): Boolean;
var
aData: PMyrec;
begin
aData := PMyrec(Msg.LParam);
ShowMessage(aData^.Name);
Handled := True;
Result := Handled;
end;
При нажатии кнопки в приложении MainApps, отправляется сообщение с данными в приложение SubApps, но в SubApps данные не удается получить корректно, так как адрес, созданный в MainApps, является мусором в SubApps.
Решение:
Чтобы передавать данные между процессами с помощью SendMessage, следует использовать сообщение WM_CopyData. Это сообщение копирует данные из одного процесса в другой, гарантируя, что данные будут корректно получены в целевом процессе.
Ниже представлен пример, иллюстрирующий использование WM_CopyData для передачи данных между процессами:
MainApps.pas:
procedure TForm1.ButtonSendClick(Sender: TObject);
var
Buffer: TMemoryStream;
Len: Integer;
CopyData: TCopyDataStruct;
Rec: TMyRec;
begin
Rec.Name := 'MyName';
Rec.Add := 'My Address';
Rec.Age := 18;
Buffer := TMemoryStream.Create;
try
Len := Length(Rec.Name);
Buffer.Write(Len, SizeOf(Len));
if Len > 0 then
Buffer.Write(Rec.Name[1], Len * SizeOf(Char));
Len := Length(Rec.Add);
Buffer.Write(Len, SizeOf(Len));
if Len > 0 then
Buffer.Write(Rec.Add[1], Len * SizeOf(Char));
Buffer.Write(Rec.Age, SizeOf(Rec.Age));
CopyData.dwData := 0;
CopyData.cbData := Buffer.Size;
CopyData.lpData := Buffer.Memory;
SendMessage(FindWindow('SubApps'), WM_CopyData, Handle, LParam(@CopyData));
finally
Buffer.Free;
end;
end;
SubApps.pas:
procedure TForm1.WMCopyData(var Message: TWMCopyData);
var
Rec: TMyRec;
Len: Integer;
Buffer: TStream;
begin
Buffer := TReadOnlyMemoryStream.Create(
Message.CopyDataStruct.lpData, Message.CopyDataStruct.cbData);
try
if Message.CopyDataStruct.dwData = 0 then begin
Buffer.Read(Len, SizeOf(Len));
SetLength(Rec.Name, Len);
if Len > 0 then
Buffer.Read(Rec.Name[1], Len * SizeOf(Char));
Buffer.Read(Len, SizeOf(Len));
SetLength(Rec.Add, Len);
if Len > 0 then
Buffer.Read(Rec.Add[1], Len * SizeOf(Char));
Buffer.Read(Rec.Age, SizeOf(Rec.Age));
// TODO: Do stuff with Rec here.
Message.Result := 1;
end else
inherited;
finally
Buffer.Free;
end;
end;
В этом примере, перед отправкой данных в MainApps, они записываются в поток памяти TMemoryStream. Затем создается структура TCopyDataStruct, в которую помещаются данные из потока памяти. После этого данные отправляются в SubApps с помощью SendMessage и WM_CopyData. В SubApps данные извлекаются из потока памяти TReadOnlyMemoryStream и помещаются в переменную Rec.
При использовании WM_CopyData для передачи данных между процессами важно учитывать, что данные, содержащие строки, представляются внутренне как указатели. Поэтому при передаче данных с помощью WM_CopyData необходимо выделить дополнительную память для хранения записи и данных строк в одном блоке памяти, чтобы целевой процесс мог прочитать их.
Вывод:
При передаче данных между процессами с помощью SendMessage и WM_MyMessage в Delphi могут возникнуть трудности, связанные с тем, что адреса имеют смысл только в пределах одного процесса. Для решения этой проблемы следует использовать сообщение WM_CopyData, которое гарантирует корректную передачу данных между процессами. При работе с данными, содержащими строки, важно учитывать, что строки представляются внутренне как указатели, и выделять дополнительную память для хранения записей и данных строк в одном блоке памяти.
В этом контексте рассматривается проблема передачи данных между двумя процессами в Delphi с использованием функции `SendMessage` и пользовательского сообщения `WM_MyMessage`. При этом возникает трудность, связанная с тем, что адреса, созданные в одном про
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.