Author: Tomas Rutkauskas
I need to capture the text from a scrolling text window in another program that I
don't have access to only through a window handle. Can I use SendMEssage or
something to ge the text with WM_GETTEXT type message. I know there are programs
like spell checkers that can do this. Any help would be appreciated.
Answer:
Solve 1:
The example runs 'chkdsk.exe c:\' and displays the output to Memo1. Put a TMemo
(Memo1) and a TButton (Button1) on your form. Put this code in the OnCLick of
Button1:
1
2 procedure TForm1.Button1Click(Sender: TObject);
3
4 procedure RunDosInMemo(DosApp: string; AMemo: TMemo);
5 const
6 ReadBuffer = 2400;
7 var
8 Security: TSecurityAttributes;
9 ReadPipe, WritePipe: THandle;
10 start: TStartUpInfo;
11 ProcessInfo: TProcessInformation;
12 Buffer: Pchar;
13 BytesRead: DWord;
14 Apprunning: DWord;
15 begin
16 with Security do
17 begin
18 nlength := SizeOf(TSecurityAttributes);
19 binherithandle := true;
20 lpsecuritydescriptor := nil;
21 end;
22 if Createpipe(ReadPipe, WritePipe, @Security, 0) then
23 begin
24 Buffer := AllocMem(ReadBuffer + 1);
25 FillChar(Start, Sizeof(Start), #0);
26 start.cb := SizeOf(start);
27 start.hStdOutput := WritePipe;
28 start.hStdInput := ReadPipe;
29 start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
30 start.wShowWindow := SW_HIDE;
31 if CreateProcess(nil, PChar(DosApp), @Security, @Security, true,
32 NORMAL_PRIORITY_CLASS, nil, nil, start, ProcessInfo) then
33 begin
34 repeat
35 Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 100);
36 Application.ProcessMessages;
37 until
38 (Apprunning <> WAIT_TIMEOUT);
39 repeat
40 BytesRead := 0;
41 ReadFile(ReadPipe, Buffer[0],
42 ReadBuffer, BytesRead, nil);
43 Buffer[BytesRead] := #0;
44 OemToAnsi(Buffer, Buffer);
45 AMemo.Text := AMemo.text + string(Buffer);
46 until
47 (BytesRead < ReadBuffer);
48 end;
49 FreeMem(Buffer);
50 CloseHandle(ProcessInfo.hProcess);
51 CloseHandle(ProcessInfo.hThread);
52 CloseHandle(ReadPipe);
53 CloseHandle(WritePipe);
54 end;
55 end;
56
57 begin {Button1 code}
58 RunDosInMemo('chkdsk.exe c:\', Memo1);
59 end;
Unfortunaly that will only work with applications that send output to stdout. A
Windows application usually doesn't do this.
Solve 2:
The usually use different techiques, like OCR on a screen bitmap. There is simply
no generic method to get text from other windows. What you can try, however, is
this:
60
61 function GetTextFromWindow(wnd: HWND): string;
62 var
63 count: Cardinal;
64 begin
65 result := '';
66 if SendMessageTimeout(wnd, WM_GETTEXTLENGTH, 0, 0,
67 SMTO_ABORTIFHUNG, 1000, count) <> 0 then
68 begin
69 if count = 0 then
70 Exit;
71 SetLength(result, count);
72 if SendMessageTimeout(wnd, WM_GETTEXT, count + 1, lparam(@result[1]),
73 SMTO_ABORTIFHUNG, 1000, count) = 0 then
74 result := '';
75 end;
76 end;
77
78 procedure TForm1.Button1Click(Sender: TObject);
79 var
80 wnd: HWND;
81 begin
82 wnd := FindWindow('notepad', nil);
83 if wnd <> 0 then
84 begin
85 wnd := GetWindow(wnd, GW_CHILD);
86 if wnd <> 0 then
87 memo1.text := GetTextfromwindow(wnd);
88 end
89 else
90 memo1.text := 'Notepad not running.';
91 end;
|