我正在尝试使用C#中的SendMessage在Notepad ++中检索文档文本。以下是我目前的代码。第一次调用SendMessage会正确返回文本的长度。对SendMessage的第二次调用不会将文本插入StringBuilder变量文本中。为什么不呢?
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
static extern int SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder lParam);
var length = SendMessage(hWnd, 2183, 0,0);
var text = new StringBuilder(length +1);
SendMessage(hWnd, 2182, length + 1, text);
答案 0 :(得分:5)
问题是您向lParam中具有StringBuilder缓冲区地址的Scintilla控件发送消息,但Notepad ++中的Scintilla控件位于不同的地址空间中,因此它接收的窗口消息中的地址可以不写信给。标准消息(如 WM_GETTEXT 和 WM_SETTEXT )的处理方式是为您执行必要的地址映射,但Scintilla控件使用的特殊消息不会发生这种情况。有关查找编组的更多信息。
不幸的是,对 WM_GETTEXTLENGTH 和 WM_GETTEXT 的支持正逐步退出Scintilla控件,文档建议使用特殊的 SCI_XXX 消息。 Notepad ++已无法与 WM_GETTEXT 一起使用,因此您需要使用 SCI_GETTEXTLENGTH (2183)和 SCI_GETTEXT (2182),并自行进行编组。
警告:在没有特殊处理缓冲区地址的情况下从其他应用程序发送SCI_GETTEXT消息实际上很危险 - Notepad ++会将数据复制到缓冲区,但由于该地址在其中无效自己的地址空间可能会立即导致访问冲突,或者(更糟糕的是)它可能会无声地覆盖内部数据。
您可以使用VirtualAllocEx()和ReadProcessMemory()来使用具有Notepad ++可用地址的缓冲区。我已经整理了一个适合我的快速Delphi程序,重要的代码就是:
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;
这是使用Ansi版API函数的早期Delphi版本,您可能会使用SendMessageW和WideChar缓冲区,但一般的想法应该是明确的。
答案 1 :(得分:1)
我在一些摆弄之后得到了它。
在VirtualFreeEx中使用MEM_RELEASE
时,我认为大小必须为0
,否则该函数将返回false
。