Reputation: 45
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!!!
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.
Upvotes: 1
Views: 300
Reputation: 595782
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');
Upvotes: 2