5

I am trying to understand how are pointers to strings working. I have a code (not exactly original), which was written by somebody, and the person is not around here anymore, so I need to understand the idea of such usage.

var
  STR: string;
  pStr: ^string;
begin
  STR := 'Hello world';
  New(pStr);
  pStr^ := STR;

  PostMessage(Handle, WM_USER+1, wParam(pStr), 0);
end;

Now I know for sure, that a message handler gets the message and the pointer contains the string, which can be worked with, but what happens 'under the hood' of those operations ?

I tried to make a small project. I thought, that assigning string to what a str pointer is pointing to would actually increase refcount of the original string and not make any copies of a string, but refcount remained 1 and it seems it did copy the contents.

So get the question, what happened? Calling New on a pointer allocates an empty string, right? After assignment I tried to look at refcount/length of a string the pointer pointed to like this PChar(@pStr^[1])[-8] but it returned nonsense (14), and the length byte was also wrong.

Additionally the questioin is, is it safe using pointers in such a way to pass on the string through windows messaging?

4
  • 2
    Such data transfer is safe. But also risky, because if the recipient doesn't receive the message you're posting, or if that recipient doesn't release that allocated memory for some reason, you get a leak. Commented Oct 22, 2013 at 7:53
  • 1
    With WM_COPYDATA you can send any data to any recipient, for this its made. No need to create other solutions. Commented Oct 22, 2013 at 8:08
  • @TLama, what are the cases where the recipient wouldn't receive the message? Commented Oct 22, 2013 at 12:31
  • 2
    @Marcus, if the recipient doesn't exist or is destroyed before the message arrives e.g. This technique is unsafe. You just post a message and let it floating in a hope it arrives somewhere. If not, you have a leak. Commented Oct 22, 2013 at 12:37

1 Answer 1

9

New(pStr) allocates a string on the heap and returns a pointer to it. Because string is a managed type, the string is default initialized, to the empty string. Since a string is implemented as a pointer, what you fundamentally have is a pointer to a pointer.

You code is perfectly fine, so long as you only post the message to your own process. Since the payload of the message is a pointer, it only means something in the context of the virtual address space of your process. If you wanted to send to a different process you'd need an IPC mechanism.

Clearly in the code that pulls the message off the queue you need to dispose of the string. Something like this:

var
  p: ^string;
  str: string;
....
p := Pointer(wParam);
str := p^; 
Dispose(p);

Your code to query the reference count and the length is just wrong. Here's how to do it correctly:

{$APPTYPE CONSOLE}

var
  pStr: ^string;
  p: PInteger;

begin
  New(pStr);
  pStr^ := 'Hello world';

  p := PInteger(pStr^);
  dec(p);
  Writeln(p^); // length
  dec(p);
  Writeln(p^); // ref count

  Readln;
end.

Output:

11
1
Sign up to request clarification or add additional context in comments.

2 Comments

REMARK: Shouldn't it be str := string(p^); (^ added)?
@alz str := p^; suffices

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.