Home > Software engineering >  SendMessage COPYDATASTRUCT wrong string when recive in delphi
SendMessage COPYDATASTRUCT wrong string when recive in delphi

Time:11-04

I send the following c application request:

string data_to_send = "Hello World";
PCSTR lpszString = data_to_send.c_str();
COPYDATASTRUCT cds;
cds.dwData = 0; // can be anything
cds.cbData = sizeof(TCHAR) * (data_to_send.size());
cds.lpData = &lpszString;
cout << lpszString << endl;
SendMessage(Output, WM_COPYDATA, (WPARAM)Output, (LPARAM)(PVOID)&cds);

I get the structure using the following code in Delphi

var
  p : PCopyDataStruct;
  s : UTF8String;
begin
  p := PCopyDataStruct(Message.lParam);
  if (p <> nil) then
  begin
    SetString(s, PAnsiChar(p^.lpData), p^.cbData);
    ShowMessage(s);
  end else
    inherited;
end;

The string looks wrong. In the debugger, it is equal to the following

'l'#$FE#$F6#2'Hello World'#0#$10#3#$88'u'#$B#0

We see 22 bytes with an extra 4 bytes before the message. If we use CHAR instead of TCHAR, then we see 11 bytes, but again with an offset of 4 bytes

#$18#$F9#$1B#3'Hello W'

Please, help!!!

UPDATE:

Thanks to Remy Lebeau for his help, his code does everything as it was originally intended and David Heffernan for the correct remark! They saved me. Here is the working code.

CodePudding user response:

On the C side:

  • cds.dwData should not be 0. Use a more unique value, such as the result of calling RegisterWindowMessage(). Many apps, and even the VCL internally, use WM_COPYDATA for different purposes, so you don't want to get confused with someone else's message by mistake.

  • sizeof(TCHAR) should be sizeof(char) instead (or omitted entirely, since sizeof(char) is always 1).

  • cds.lpData = &lpszString; needs to be cds.lpData = lpszString; instead. You are sending the address of the lpszString variable itself, not the address of the character data it points at. That is why you are seeing garbage on the other end - you are seeing random bytes from the call stack where lpszString resides, which in your case includes the std::string object (whose internal members happen to include a Short-String-Optimization buffer, which is why you are also seeing your characters, too).

On the Delphi side:

  • you should validate p^.dwData is your unique number before processing the message any further. If the number does not match what you are expecting, pass the message to the inherited handler and move on.

  • UTF8String should be AnsiString, unless the sender's std::string is actually UTF-8 encoded.

Try this:

const UINT uMyDataID = RegisterWindowMessage(TEXT("MyDataID"));
...
if (uMyDataID != 0)
{
    string data_to_send = u8"Hello World";
    COPYDATASTRUCT cds;
    cds.dwData = uMyDataID;
    cds.cbData = sizeof(char) * data_to_send.size();
    cds.lpData = const_cast<char*>(data_to_send.c_str());
    // or: cds.lpData = data_to_send.data(); in C  17 and later
    SendMessage(Output, WM_COPYDATA, reinterpret_cast<WPARAM>(Output), reinterpret_cast<LPARAM>(&cds));
}
var
  uMyDataID: UINT = 0;
...
procedure TMyForm.WMCopyData(var Message: TMessage);
var
  p : PCopyDataStruct;
  s : UTF8String;
begin
  p := PCopyDataStruct(Message.lParam);
  if (uMyDataID <> 0) and (p <> nil) and (p^.dwData = uMyDataID) then
  begin
    SetString(s, PAnsiChar(p^.lpData), p^.cbData);
    ShowMessage(s);
  end else
    inherited;
end;
...
initialization
  uMyDataID := RegisterWindowMessage('MyDataID');
  • Related