2

This code used to work with Delphi 5, but with delphi XE2 does not work as expected. The string passed using wm_copydata will be cut.

procedure SendAppParameters(aMsgStr: string);
var
  hwnd: THandle;
  cds: CopyDataStruct;
begin


  hwnd := FindWindow('TMyAppFormMain', nil); //<-- Substitute window classname with your own
  if hwnd <> 0 then
  begin
   // showmessage(aMsgStr);
    // prepare the data to copy
    cds.dwData := 0;
    cds.cbData := length(AMsgStr);
    cds.lpData := PChar(AMsgStr);
    // activate the destination window
    SetForegroundWindow(hwnd);
    // send the data to the first instance using a wm_CopyData message
    SendMessage(hwnd, wm_CopyData, Application.Handle, integer(@cds));
  end

end;

And in the Main Form I have:

procedure TMyAppFormMain.GotMessage_CopyData(var Msg: TWmCopyData);
var
  MsgString: string;
  I: Integer;
begin

  MsgString := PChar(Msg.CopyDataStruct.lpData);
  showmessage(MsgString);


end;
user1238784
  • 2,250
  • 3
  • 22
  • 41
  • 2
    The `cbData` member of the `COPYDATASTRUCT` structure is a size in bytes, so you need to set there `Length(AMsgStr) * SizeOf(Char)` since from Delphi 2009, chars are 2 bytes in size. – TLama Apr 12 '14 at 13:51
  • 1
    thanks that solved it, and also I replaced integer(@cds)) with LPARAM(@cds). – user1238784 Apr 12 '14 at 13:53

1 Answers1

4

In fact your code has never been correct. It is broken even on ANSI versions of Delphi.

Let's take a look. You prepare the message like this:

cds.cbData := length(AMsgStr);
cds.lpData := PChar(AMsgStr);

On an ANSI Delphi that means that the text is marshalled up to but not including the null-terminator.

The receiver does this:

MsgString := PChar(Msg.CopyDataStruct.lpData);

This relies on there being a null-terminator present. There's no reason to expect that there would be and even to attempt to read beyond cds.cbData bytes is an error.

The recipient must take care to heed the value of cds.cbData that is sent and not read beyond the end of the buffer.

Now, the other issue is that you have moved to a Unicode Delphi and so text is now UTF-16 encoded.

To send the text I would write:

cds.cbData := length(AMsgStr)*SizeOf(Char);
cds.lpData := PChar(AMsgStr);

And on the receiving side it should be:

SetString(MsgString, PChar(Msg.CopyDataStruct.lpData), 
  Msg.CopyDataStruct.cbData div SizeOf(Char));

The cast that you use, integer(@cds), is incorrect. That should be LPARAM(@cds).

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 4
    If you use `SizeOf(Char)` on the sender then you should use `div SizeOf(Char)` on the receiver to match. – Remy Lebeau Apr 12 '14 at 14:57
  • well it was not my code, it just some code I copied and pasted, since I never dig a lot into lower level things unless it is necessary. I see now that even the receiving part had an error, in that it is assuming the null terminated string. Thanks for pointing it out – user1238784 Apr 12 '14 at 15:56
  • 2
    This is why it's important not to copy code without checking it. – David Heffernan Apr 12 '14 at 16:00