function Process_ReadRichEditText(AHandle: THandle): WideString; var vGetTextEx: GETTEXTEX; vGetTextLengthEx: GETTEXTLENGTHEX; L: Integer;
vProcessId: DWORD; vProcess: THandle; vPointer: Pointer; vNumberOfBytesRead: Cardinal; begin Result := ‘‘; if not IsWindow(AHandle) then Exit; GetWindowThreadProcessId(AHandle, @vProcessId); vProcess := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE, False, vProcessId); try vPointer := VirtualAllocEx(vProcess, nil, 4096, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE); vGetTextLengthEx.flags := GTL_DEFAULT; vGetTextLengthEx.codepage := 1200; // Unicode WriteProcessMemory(vProcess, vPointer, @vGetTextLengthEx, SizeOf(vGetTextLengthEx), vNumberOfBytesRead); L := SendMessage(AHandle, EM_GETTEXTLENGTHEX, Integer(vPointer), 0); VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE); if L <= 0 then Exit; vPointer := VirtualAllocEx(vProcess, nil, SizeOf(vGetTextEx) + L * 2 + 2, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE); SetLength(Result, L); vGetTextEx.cb := L * 2 + 2; vGetTextEx.flags := GT_DEFAULT; vGetTextEx.codepage := 1200; // Unicode vGetTextEx.lpDefaultChar := nil; vGetTextEx.lpUsedDefChar := nil; WriteProcessMemory(vProcess, vPointer, @vGetTextEx, SizeOf(vGetTextEx), vNumberOfBytesRead); SendMessage(AHandle, EM_GETTEXTEX, Integer(vPointer), Integer(vPointer) + SizeOf(vGetTextEx)); ReadProcessMemory(vProcess, Pointer(Integer(vPointer) + SizeOf(vGetTextEx)), @Result[1], L * 2, vNumberOfBytesRead); VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE); finally CloseHandle(vProcess); end; end; { Process_ReadRichEditText }
function GetProcessName(AProcessID: THandle): string; var vBuffer: array[0..MAX_PATH] of Char; vProcess: THandle; begin vProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, AProcessID); try if GetModuleBaseName(vProcess, 0, vBuffer, SizeOf(vBuffer)) > 0 then Result := vBuffer else Result := ‘‘; finally CloseHandle(vProcess); end; end; { GetProcessName }
function EnumChild(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; var vBuffer: array[0..255] of Char; begin Result := True; if not IsWindowVisible(hwnd) then Exit; // 不可见 GetClassName(hwnd, vBuffer, SizeOf(vBuffer)); if SameText(vBuffer, ‘RichEdit20A‘) then begin if GetWindowLong(hwnd, GWL_STYLE) and ES_READONLY <> ES_READONLY then // 非只读 begin PInteger(lParam)^ := hwnd; Result := False; end; end; end; { EnumChild }
function EnumFunc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall; var vBuffer: array[0..255] of Char; vProcessId: THandle; begin Result := True; if not IsWindowVisible(hwnd) then Exit; // 不可见 GetClassName(hwnd, vBuffer, SizeOf(vBuffer)); if SameText(vBuffer, ‘#32770‘) then begin GetWindowThreadProcessId(hwnd, vProcessId); if SameText(GetProcessName(vProcessId), ‘qq.exe‘) then begin GetWindowText(hwnd, vBuffer, SizeOf(vBuffer)); if Pos(‘聊天中‘, vBuffer) > 0 then // 标题中含"聊天中" begin EnumChildWindows(hwnd, @EnumChild, lParam); Result := False; end; end; end; end; { EnumFunc }
procedure TForm1.Button1Click(Sender: TObject); var vHandle: THandle; begin vHandle := 0; EnumWindows(@EnumFunc, Integer(@vHandle)); if vHandle = 0 then Exit; Memo1.Text := Process_ReadRichEditText(vHandle); end;
using System.Runtime.InteropServices; [DllImport("User32.DLL")] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); public delegate bool WNDENUMPROC(IntPtr hwnd, int lParam); [DllImport("user32.dll")] public static extern int EnumWindows(WNDENUMPROC lpEnumFunc, int lParam); [DllImport("user32.dll")] public static extern int EnumChildWindows(IntPtr hWndParent, WNDENUMPROC lpEnumFunc, int lParam); [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32.DLL")] public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint dwProcessId); [DllImport("psapi.dll")] public static extern uint GetModuleBaseName(IntPtr hProcess, IntPtr hModule, StringBuilder lpBaseName, uint nSize); public const uint PROCESS_VM_OPERATION = 0x0008; public const uint PROCESS_VM_READ = 0x0010; public const uint PROCESS_VM_WRITE = 0x0020; public const uint PROCESS_QUERY_INFORMATION = 0x0400; [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr handle); [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr hWnd, int nIndex); public const int GWL_STYLE = -16; public const int ES_READONLY = 0x800; public const uint MEM_COMMIT = 0x1000; public const uint MEM_RELEASE = 0x8000; public const uint MEM_RESERVE = 0x2000; public const uint PAGE_READWRITE = 4; [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType); [DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead); [DllImport("kernel32.dll")] public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead); private IntPtr richHandle; public string GetProcessName(uint AProcessId) { StringBuilder vBuffer = new StringBuilder(256); IntPtr vProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, AProcessId); try { if (GetModuleBaseName(vProcess, IntPtr.Zero, vBuffer, (uint)vBuffer.Capacity) > 0) return vBuffer.ToString(); else return string.Empty; } finally { CloseHandle(vProcess); } } public bool EnumChild(IntPtr hwnd, int lParam) { if (!IsWindowVisible(hwnd)) return true; // 不可见 StringBuilder vBuffer = new StringBuilder(256); GetClassName(hwnd, vBuffer, vBuffer.Capacity); if (vBuffer.ToString().ToLower() == "richedit20a") { if ((GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY) != ES_READONLY) // 非只读 { richHandle = hwnd; return false; } } return true; } public bool EnumFunc(IntPtr hwnd, int lParam) { if (!IsWindowVisible(hwnd)) return true; // 不可见 StringBuilder vBuffer = new StringBuilder(256); GetClassName(hwnd, vBuffer, vBuffer.Capacity); if (vBuffer.ToString() == "#32770") { uint vProcessId; GetWindowThreadProcessId(hwnd, out vProcessId); if (GetProcessName(vProcessId).ToLower() == "qq.exe") { GetWindowText(hwnd, vBuffer, vBuffer.Capacity); if (vBuffer.ToString().IndexOf("聊天中") >= 0) // 标题中含"聊天中" { EnumChildWindows(hwnd, @EnumChild, lParam); return false; } } } return true; } [StructLayout(LayoutKind.Sequential)] public struct GETTEXTLENGTHEX { public uint flags; public uint codepage; } [StructLayout(LayoutKind.Sequential)] public struct GETTEXTEX { public int cb; public int flags; public int codepage; public IntPtr lpDefaultChar; public IntPtr lpUsedDefChar; }; public const int GTL_DEFAULT = 0; public const int GT_DEFAULT = 0; public const int WM_USER = 0x0400; public const int EM_GETTEXTEX = WM_USER + 94; public const int EM_GETTEXTLENGTHEX = WM_USER + 95; public string Process_ReadRichEditText(IntPtr AHandle) { if (!IsWindow(AHandle)) return string.Empty; string vReturn = string.Empty; uint vProcessId; GetWindowThreadProcessId(AHandle, out vProcessId); IntPtr vProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, vProcessId); try { uint vNumberOfBytesRead = 0; IntPtr vPointer = VirtualAllocEx(vProcess, IntPtr.Zero, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); GETTEXTLENGTHEX vGetTextLengthEx = new GETTEXTLENGTHEX(); vGetTextLengthEx.flags = GTL_DEFAULT; vGetTextLengthEx.codepage = 1200; // Unicode IntPtr vAddress = Marshal.AllocCoTaskMem(Marshal.SizeOf(vGetTextLengthEx)); Marshal.StructureToPtr(vGetTextLengthEx, vAddress, false); WriteProcessMemory(vProcess, vPointer, vAddress, Marshal.SizeOf(vGetTextLengthEx), ref vNumberOfBytesRead); Marshal.FreeCoTaskMem(vAddress); int L = SendMessage(AHandle, EM_GETTEXTLENGTHEX, (int)vPointer, 0); VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE); if (L <= 0) return vReturn; GETTEXTEX vGetTextEx = new GETTEXTEX(); vGetTextEx.cb = L * 2 + 2; vGetTextEx.flags = GT_DEFAULT; vGetTextEx.codepage = 1200; // Unicode vGetTextEx.lpDefaultChar = IntPtr.Zero; vGetTextEx.lpUsedDefChar = IntPtr.Zero; vPointer = VirtualAllocEx(vProcess, IntPtr.Zero, (uint)(Marshal.SizeOf(vGetTextEx) + L * 2 + 2), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); vAddress = Marshal.AllocCoTaskMem(Marshal.SizeOf(vGetTextEx)); Marshal.StructureToPtr(vGetTextEx, vAddress, false); WriteProcessMemory(vProcess, vPointer, vAddress, Marshal.SizeOf(vGetTextEx), ref vNumberOfBytesRead); Marshal.FreeCoTaskMem(vAddress); SendMessage(AHandle, EM_GETTEXTEX, (int)vPointer, (int)vPointer + Marshal.SizeOf(vGetTextEx)); vAddress = Marshal.AllocCoTaskMem(L * 2); ReadProcessMemory(vProcess, (IntPtr)((int)vPointer + Marshal.SizeOf(vGetTextEx)), vAddress, L * 2, ref vNumberOfBytesRead); vReturn = Marshal.PtrToStringUni(vAddress, L * 2); Marshal.FreeCoTaskMem(vAddress); VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE); } finally { CloseHandle(vProcess); } return vReturn; } private void button1_Click(object sender, EventArgs e) { richHandle = IntPtr.Zero; EnumWindows(EnumFunc, 0); if (richHandle == IntPtr.Zero) return; Console.WriteLine(Process_ReadRichEditText(richHandle)); }