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

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

问题描述:

我想让Delphi应用程序通过WM_COPYDATA与其他应用程序进行通信。我遇到的问题是发件人应用程序是用Delphi 7编写的,而接收器是用Delphi 10.2编写的。我将Delphi 7程序的代码复制到了Delphi 10中,并且通信非常完美。然而,在Delphi 7中使用完全相同的代码却导致我的字符串被传递给接收器应用程序以损坏。是我使用的代码如下:通过WM_COPYDATA在不同的Delphi版本应用程序之间传输数据

一个发送端,我有:

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发送的消息字符串被破坏?

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

+1

这将是最好使用'WideChar'用UTF-16发送数据,或使用UTF-8'AnsiChar'。根本不要使用ANSI。 –

+0

@RemyLebeau谢谢你,在此期间计算出来,但不知道如何转换数据。 –

+0

您需要取消引用您在Move()中第一个参数传递的指针,并在第二个参数中删除“@”:Move(PAnsiChar(p^.lpData)^,S [1],l )'。另外,你的'cbData'值已经包含null结束符,所以你不需要在接收端使用'+ 1'。如果有的话,你应该使用'-1'来忽略空终止符。或者更好的是,根本不发送空终止符,你不需要它 –

您正在使用本机编码Char发送和处理数据,这是在Delphi 7中为AnsiChar,但在Delphi 10.2 Tokyo(德尔福在D2009中将所有内容切换为Unicode)都是WideChar。当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');