The problem is that you send a message to the Scintilla control that has the address of your StringBuilder buffer in the lParam, but the Scintilla control in Notepad++ lives in a different address space, so the address in the window message it receives can not be written to. Standard messages like WM_GETTEXT and WM_SETTEXT are handled in a way that the necessary address mapping is performed for you, but this does not happen for the special messages the Scintilla control uses. For more information lookup marshalling.
Unfortunately support for WM_GETTEXTLENGTH and WM_GETTEXT is being phased out of the Scintilla control, and the documentation advises to use the special SCI_XXX messages. Notepad++ does already not work with WM_GETTEXT, so you need to use SCI_GETTEXTLENGTH (2183) and SCI_GETTEXT (2182), and do the marshalling yourself.
Warning: It is actually dangerous to send the SCI_GETTEXT message from another application without special handling of the buffer address - Notepad++ will copy the data to the buffer, but since the address is not valid in its own address space this can cause an access violation immediately, or (worse) it could silently overwrite internal data.
You can use VirtualAllocEx() and ReadProcessMemory() to use a buffer with an address usable by Notepad++. I have put together a quick Delphi program that works for me, the important code is this:
procedure TForm1.Button1Click(Sender: TObject);
const
VMFLAGS = PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE;
var
Wnd: HWND;
Len: integer;
ProcessId, BytesRead: Cardinal;
ProcessHandle: THandle;
MemPtr: PChar;
s: string;
begin
Wnd := $30488;
Len := SendMessage(Wnd, 2183, 0, 0);
if Len > 0 then begin
GetWindowThreadProcessId(Wnd, @ProcessId);
ProcessHandle := OpenProcess(VMFLAGS, FALSE, ProcessId);
MemPtr := VirtualAllocEx(ProcessHandle, nil, Len + 1,
MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
if MemPtr <> nil then try
SendMessage(Wnd, 2182, Len + 1, integer(MemPtr));
SetLength(s, Len + 1);
ReadProcessMemory(ProcessHandle, MemPtr, @s[1], Len + 1, BytesRead);
SetLength(s, BytesRead);
Memo1.Lines.Text := s;
finally
VirtualFreeEx(ProcessId, MemPtr, Len + 1, MEM_RELEASE);
end;
end;
end;
This is an earlier Delphi version using the Ansi version of the API functions, you would probably use SendMessageW and a WideChar buffer, but the general idea should be clear.