Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用SendMessage从闪烁控件检索文本_C#_Sendmessage_Scintilla - Fatal编程技术网

C# 使用SendMessage从闪烁控件检索文本

C# 使用SendMessage从闪烁控件检索文本,c#,sendmessage,scintilla,C#,Sendmessage,Scintilla,我正在尝试使用C#中的SendMessage检索Notepad++中的文档文本。下面是我当前的代码。对SendMessage的第一次调用将正确返回文本的长度。对SendMessage的第二次调用不会将文本插入StringBuilder变量文本中。为什么不呢 [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] static extern int SendMessage(IntPt

我正在尝试使用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);

问题是,您向Slinklla控件发送一条消息,该消息在LPRAM中包含StringBuilder缓冲区的地址,但Notepad++中的Slinklla控件位于不同的地址空间中,因此无法写入它接收的窗口消息中的地址。WM_GETTEXT和WM_SETTEXT等标准消息的处理方式是为您执行必要的地址映射,但闪烁控件使用的特殊消息不会发生这种情况。有关详细信息,请查阅编组

不幸的是,对WM_GETTEXTLENGTH和WM_GETTEXT的支持正在逐步退出闪烁控制,文档建议使用特殊的SCI_XXX消息。Notepad++已经不能与WM_GETTEXT一起使用,因此您需要使用SCI_GETTEXTLENGTH(2183)和SCI_GETTEXT(2182),并自己进行编组

警告:从另一个应用程序发送SCI_GETTEXT消息而不特别处理缓冲区地址实际上是危险的-记事本++会将数据复制到缓冲区,但由于地址在其自己的地址空间中无效,这可能会立即导致访问冲突,或者(更糟)它可以悄悄地覆盖内部数据


您可以使用VirtualAllocEx()和ReadProcessMemory()使用一个缓冲区,该缓冲区的地址可由记事本++使用。我已经编写了一个适用于我的快速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;
procedure TForm1.按钮1点击(发送方:TObject);
常数
VMFLAGS=进程虚拟机操作或进程虚拟机读取或进程虚拟机写入;
变量
Wnd:HWND;
Len:整数;
ProcessId,字节读:基数;
ProcessHandle:THandle;
MemPtr:PChar;
s:字符串;
开始
Wnd:=30488美元;
Len:=发送消息(Wnd,2183,0,0);
如果Len>0,则开始
GetWindowThreadProcessId(Wnd,@ProcessId);
ProcessHandle:=OpenProcess(VMFLAGS,FALSE,ProcessId);
MemPtr:=VirtualAllocEx(ProcessHandle,nil,Len+1,
MEM_RESERVE或MEM_COMMIT,PAGE_READWRITE);
如果MemPtr为零,则尝试
SendMessage(Wnd,2182,Len+1,integer(MemPtr));
设定长度(s,Len+1);
ReadProcessMemory(ProcessHandle,MemPtr,@s[1],Len+1,BytesRead);
设置长度(s,字节读取);
Memo1.Lines.Text:=s;
最后
VirtualFreeEx(ProcessId、MemPtr、Len+1、MEM_发布);
结束;
结束;
结束;

这是一个早期的Delphi版本,使用Ansi版本的API函数,您可能会使用SendMessageW和WideChar缓冲区,但总体思路应该很清楚。

我在做了一些修改之后才使它工作起来


在VirtualForeex中使用
MEM\u RELEASE
时,我相信大小必须是
0
,否则函数将返回
false

谢谢提示!那么,我是否能够使用VirtualAllocEx分配一些内存,然后在SendMessage中传递内存?我怎样才能从记事本++中检索文档文本?我让它工作了。我错过了OpenProcess调用。我还尝试使用.Net framework中提供的Marhal类读取内存。我必须调查一下为什么那种方法行不通。再次感谢!