Search code examples
stringdelphipointersdelphi-7

Using string pointer to send a string through windows messages


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?


Solution

  • 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