Postmessage LParam truncation
Asked Answered
H

1

1

My app has a worker thread, and I use PostMessage to send a string to the main thread. For 1 message, the string is truncated when it gets to the message handler in the main thread.

The string is constructed in the worker thread from a string of raw data that is like this. It ends at the last '20'.

'01010000000030000102000008850008855343414E204544474520000000000000000000'

Decoded into the string I want to send it looks like this, which is correct:

'0100 0.50000 LSB0288.588.5SCAN EDGE '

The code that creates the 'SCAN EDGE ' portion and posts it is: tmp and s_out are strings

x := 35;
for i := 1 to 10 do
begin
  tmp := '$' + copy(s,x,2);
  TryStrToInt(tmp,dec);
  s_out := s_out + chr(dec);
  x := x + 2;
end;
PostMessage(MainHandle,UM_CLONE, UM_756, Integer(PChar(s_out)));

The message handler in the main thread is: i is a string

i := pChar(msg.LParam);

when it gets to the main thread i looks like this in the debugger:

'0100 0.50000 LSB0288.588.5SCAN EDG'#0

How can I correct this?

Hysterical answered 29/3, 2012 at 19:30 Comment(0)
A
12

You are posting the contents of a String variable that is local to the thread procedure that is calling PostMessage(). If the String goes out of scope and gets freed before the main thread processes the posted message, the memory will be garbage.

You need to either:

1) use SendMessage() instead of PostMessage() so the String stays in scope until the message handler exits:

SendMessage(MainHandle, UM_CLONE, UM_756, LPARAM(PChar(s_out)));

2) dynamically allocate a String in memory, fill it as needed, post it, and then let the main message handler free it when it is done copying it:

var
  s_out: PString;

New(s_out);
...
s_out^ := s_out^ + chr(dec);
...
if not PostMessage(MainHandle, UM_CLONE, UM_756, LPARAM(s_out)) then
  Dispose(s_out);

.

var
  ps: PString;
  i: String;

ps := PString(msg.LParam);
i := ps^;
Dispose(ps);

PS: notice I also changed your Integer() cast to LPARAM(). This is very important if you ever upgrade to Delphi XE2 or later. PostMessage() and SendMessage() use LPARAM, not Integer. You can get away with it in Delphi 7 because LPARAM is an alias for Integer in that version, but that is not the case anymore in modern Delphi versions. LPARAM is an alias for NativeUInt now. LPARAM has always been an unsinged type in the Win32 API, Delphi just got it wrong in the early versions, but Embarcadero has really been pushing for type-correctness in the RTL/VCL since adding support for 64-bit and cross-platform development. If you don't match the right data types correctly, you can cause range checks errors and such at runtime.

Ailing answered 29/3, 2012 at 21:41 Comment(2)
It will work only within the same process. For interprocess communication using messages, use WM_COPY, which will marshall the content as expected.Upswell
You are thinking of WM_COPYDATA instead.Ailing

© 2022 - 2024 — McMap. All rights reserved.