通过WM_COPYDATA在不同的Delphi版本应用程序之间传输数据

时间:2017-11-25 15:38:14

标签: delphi wm-copydata

我试图让Delphi应用程序通过WM_COPYDATA相互通信。我遇到的问题是发件人应用程序是用Delphi 7编写的,接收器是用Delphi 10.2编写的。我将我的Delphi 7程序代码复制到Delphi 10中,并且通信工作完美。然而,在Delphi 7中使用完全相同的代码会导致我的字符串被传递到接收器应用程序以便被破坏。我使用的代码如下:

我有一个发送方:

procedure TSenderApp.SendString(ToSend: string);
var
 copyDataStruct : TCopyDataStruct;

  receiverHandle : THandle;
   res : integer;
begin
 copyDataStruct.dwData := 140500; //use it to identify the message contents
 copyDataStruct.cbData := (1+ Length(ToSend))* SizeOf(Char) ;
 copyDataStruct.lpData := pchar(ToSend) ;

 receiverHandle := FindWindow(PChar('TRecieverApp'),PChar('RecieverApp')) ;
   if receiverHandle = 0 then
   begin
     ShowMessage('CopyData Receiver NOT found!') ;
     Exit;
   end;

   res := SendMessage(receiverHandle, WM_COPYDATA, Integer(Handle), 
   LPARAM(@copyDataStruct)) ;
end;

在接收方面,我有:

procedure TRecieverApp.WMCopyData(var Message: TMessage);
var
  p : PCopyDataStruct;
  l : Integer;
  s : string;
begin
  p := PCopyDataStruct( Message.lParam );

  if (p <> nil) then
  begin
  ShowMessage('New Message Recieved!');
    l := p^.cbData;
    SetLength( s, (l+1) );
    StrLCopy( PChar(s), PChar(p^.lpData), l );
    Edit1.Text := s;
  end
  else
    Edit1.Text := 'ERROR';
end;

我做错了什么?或者,为什么消息字符串在从Delphi 7编写的SenderApp发送而不是从Delphi 10编写的SenderApp发送时被破坏?

2 个答案:

答案 0 :(得分:6)

您正在使用Char的本机编码发送和处理数据,在Delphi 7中为AnsiChar,但在Delphi 10.2中为WideChar(Delphi在D2009中将所有内容切换为Unicode) 。当Delphi 7将数据发送为ANSI时,Delphi 10.2将其误解为UTF-16。反之亦然。所以你最终都会以腐败结束。

您需要在发送数据之前将数据转换为商定的字符编码,并在接收后将其从该编码转换。

尝试更像这样的事情:

{$IF CompilerVersion >= 24} // XE3+
{$LEGACYIFEND ON} 
{$IFEND}

var
  MyDataID: UINT = 0;

procedure TSenderApp.SendString(const ToSend: string);
var
  copyDataStruct : TCopyDataStruct;
  receiverHandle : HWND;
  res : LRESULT;
  s : UTF8String;
begin
  if MyDataID = 0 then
  begin
    ShowMessage('CopyData ID NOT registered!');
    Exit;
  end;

  receiverHandle := FindWindow('TRecieverApp', 'RecieverApp');
  if receiverHandle = 0 then
  begin
    ShowMessage('CopyData Receiver NOT found!');
    Exit;
  end;

  {$IF CompilerVersion >= 20} // D2009+
  s := UTF8String(ToSend);
  {$ELSE}
  s := UTF8Encode(ToSend);
  {$IFEND}

  copyDataStruct.dwData := MyDataID; //use it to identify the message contents
  copyDataStruct.cbData := Length(s) * SizeOf(AnsiChar);
  copyDataStruct.lpData := PAnsiChar(s);
  res := SendMessage(receiverHandle, WM_COPYDATA, WPARAM(Handle), LPARAM(@copyDataStruct));
end;

initialization
  MyDataID := RegisterWindowMessage('MyDataID');

{$IF CompilerVersion >= 24} // XE3+
{$LEGACYIFEND ON} 
{$IFEND}

var
  MyDataID: UINT = 0;

procedure TRecieverApp.WMCopyData(var Message: TMessage);
var
  p : PCopyDataStruct;
  s : UTF8String;
begin
  p := PCopyDataStruct(Message.lParam);
  if (p <> nil) and (MyDataID <> 0) and (p^.dwData = MyDataID) then
  begin
    SetString(s, PAnsiChar(p^.lpData), p^.cbData);
    {$IF CompilerVersion >= 20} // D2009+
    Edit1.Text := String(s);
    {$ELSE}
    Edit1.Text := UTF8Decode(s);
    {$IFEND} 
    ShowMessage('New Message Received!');
  end else
    inherited;
end;

initialization
  MyDataID := RegisterWindowMessage('MyDataID');

答案 1 :(得分:1)

两个Delphi版本之间的区别是字符串格式。在Delphi 2007及更早版本中,string使用ANSI格式的1字节AnsiChar字符。在Delphi 2009及更高版本中,string使用UTF-16格式的2字节WideChar字符。您需要在发送数据时将数据转换为通用字符编码。