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 callingRegisterWindowMessage()
. Many apps, and even the VCL internally, useWM_COPYDATA
for different purposes, so you don't want to get confused with someone else's message by mistake.sizeof(TCHAR)
should besizeof(char)
instead (or omitted entirely, sincesizeof(char)
is always 1).cds.lpData = &lpszString;
needs to becds.lpData = lpszString;
instead. You are sending the address of thelpszString
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 wherelpszString
resides, which in your case includes thestd::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 theinherited
handler and move on.UTF8String
should beAnsiString
, unless the sender'sstd::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');