xo310
asked on
Getting text from a richedit control in another application
Hi, Please take a look at this image to see the richedit I am talking about.
http://geocities.com/oalawneh/daimage.jpg
It is my first time playing with api so I was stuck several times. Nevertheless it is still a source of fun:-).
Now I could get the handle of the parent client and consequently its titlebar text. like this:
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, StrUtils;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender : TObject);
var
DeskTopHwnd, WindowHwnd: Hwnd;
Buff : array[0..255] of char;
begin
label1.update;
DeskTopHwnd := GetDeskTopWindow;
WindowHwnd := GetWindow(DeskTopHwnd,GW_C HILD);
While WindowHwnd <> 0 do
begin
GetWindowText(WindowHwnd,B uff,255);
if (Buff <> '') AND (IsWindowVisible(WindowHwn d) <> False) and
(AnsiContainsText(Buff, 'holdem')=true)
then
begin
label1.Caption:=buff;
end;
WindowHwnd := GetWindow(WindowHwnd,GW_HW NDNEXT);
end;
end;
end.
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- --------
Now this works for the parent window. But could not figure out how to get the handle of the richedit in the application client window and consequently getting its text to place in a memo or a richedit.
Which functions should i use?
http://geocities.com/oalawneh/daimage.jpg
It is my first time playing with api so I was stuck several times. Nevertheless it is still a source of fun:-).
Now I could get the handle of the parent client and consequently its titlebar text. like this:
--------------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, StrUtils;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender
var
DeskTopHwnd, WindowHwnd: Hwnd;
Buff : array[0..255] of char;
begin
label1.update;
DeskTopHwnd := GetDeskTopWindow;
WindowHwnd := GetWindow(DeskTopHwnd,GW_C
While WindowHwnd <> 0 do
begin
GetWindowText(WindowHwnd,B
if (Buff <> '') AND (IsWindowVisible(WindowHwn
(AnsiContainsText(Buff, 'holdem')=true)
then
begin
label1.Caption:=buff;
end;
WindowHwnd := GetWindow(WindowHwnd,GW_HW
end;
end;
end.
--------------------------
Now this works for the parent window. But could not figure out how to get the handle of the richedit in the application client window and consequently getting its text to place in a memo or a richedit.
Which functions should i use?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Btw, in that picture it looks like a ListBox, not RichText. For ListBox'es there's some other technique of getting text. You'll have to get every line (probably with SendMessage() function with LB_GETTEXT message to get text of item and LB_GETCOUNT message to get count of items)
Here it is:
var
wnd : hwnd;
txt : pchar;
n : integer;
cnt : integer;
len : integer;
begin
.....
get a handle of listbox, just the same way as in my first post
.....
cnt := SendMessage(wnd, lb_getcount, 0, 0);
for n := 0 to cnt - 1 do begin
len := SendMessage(wnd, lb_gettextlen, n, 0);
GetMem(txt, len + 1);
SendMessage(wnd, lb_gettext, n, integer(txt));
Memo1.Lines.Append(txt);
FreeMem(txt);
end;
end;
var
wnd : hwnd;
txt : pchar;
n : integer;
cnt : integer;
len : integer;
begin
.....
get a handle of listbox, just the same way as in my first post
.....
cnt := SendMessage(wnd, lb_getcount, 0, 0);
for n := 0 to cnt - 1 do begin
len := SendMessage(wnd, lb_gettextlen, n, 0);
GetMem(txt, len + 1);
SendMessage(wnd, lb_gettext, n, integer(txt));
Memo1.Lines.Append(txt);
FreeMem(txt);
end;
end;
ASKER
zhaawz thank you. Let me try your method and feed you back very soon.
thanks
thanks
ASKER
Zhaawz, I used Greatis WinDowse to know the class name of that control and it said richedit.
I saved the first method in my notes for future use thank you. But what I need is a little bit different.
Once the handle is known, <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/indivcontrol.asp" target="_blank">I know how to get text from it</a>.
to summarize, We know there is a string "dealer:" in the control and it is not present anywhere else in the client window. Can we find the class name and handle of the control without using the mouse? Just as i did with the client window?
Basically, my code detected all running windows then chose the one with the word "holdem" as it is seen from my code. But I could not do the same for the control.
Thanks for your patience:-)
I saved the first method in my notes for future use thank you. But what I need is a little bit different.
Once the handle is known, <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/indivcontrol.asp" target="_blank">I know how to get text from it</a>.
to summarize, We know there is a string "dealer:" in the control and it is not present anywhere else in the client window. Can we find the class name and handle of the control without using the mouse? Just as i did with the client window?
Basically, my code detected all running windows then chose the one with the word "holdem" as it is seen from my code. But I could not do the same for the control.
Thanks for your patience:-)
ASKER
About mouse - that's needed only 1 time - to get parents of a control you need. Next time you'll not need a mouse.
Is that game downloadable somewhere? If I had it I could try to get needed handle/text...
ASKER
Here is it:
www.partypoker.com
about 3 MB and you dont have to register to watch tables.
I think your code above was very useful so I am giving the points in advance. Thanks
www.partypoker.com
about 3 MB and you dont have to register to watch tables.
I think your code above was very useful so I am giving the points in advance. Thanks
Getting handle of this richedit is not that easy as I though at the beginning :) However, it is not impossible. Here's how I did it :)
var
wnd : cardinal;
txt : pchar;
len : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
//now we have a handle we need :)
end else begin
ShowMessage('Can''t find a window');
end;
end;
var
wnd : cardinal;
txt : pchar;
len : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
//now we have a handle we need :)
end else begin
ShowMessage('Can''t find a window');
end;
end;
ASKER
wow, this is great, it is working:-). Am very grateful. Thank you
;) Now comes a problem - I couldn't get a text from it... Tried to do like in MSDN is written, but something goes wrong - a game just crashes (I don't know why). Here's what I'm doing:
var
wnd : cardinal;
txt : pchar;
textlen : record {gettextlengthex structure}
flags : cardinal;
codepage : cardinal;
end;
text : record {gettexthex structure}
cb : cardinal;
flags : cardinal;
codepage : cardinal;
lpDefaultChar : pchar;
lpUsedDefChar : cardinal;
end;
len : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
textlen.flags := 0 {gtl_default};
textlen.codepage := cp_acp;
len := SendMessage(wnd, wm_user + 95 {em_gettextlengthex}, integer(@textlen), 0);
GetMem(txt, len + 1);
text.cb := len;
text.flags := 0 {gt_default};
text.codepage := cp_acp;
text.lpDefaultChar := nil;
text.lpUsedDefChar := 0;
SendMessage(wnd, wm_user + 94 {em_gettextex}, integer(@text), integer(txt));
memo1.Text := txt;
FreeMem(txt);
end else begin
ShowMessage('Can''t find a window');
end;
end;
var
wnd : cardinal;
txt : pchar;
textlen : record {gettextlengthex structure}
flags : cardinal;
codepage : cardinal;
end;
text : record {gettexthex structure}
cb : cardinal;
flags : cardinal;
codepage : cardinal;
lpDefaultChar : pchar;
lpUsedDefChar : cardinal;
end;
len : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
textlen.flags := 0 {gtl_default};
textlen.codepage := cp_acp;
len := SendMessage(wnd, wm_user + 95 {em_gettextlengthex}, integer(@textlen), 0);
GetMem(txt, len + 1);
text.cb := len;
text.flags := 0 {gt_default};
text.codepage := cp_acp;
text.lpDefaultChar := nil;
text.lpUsedDefChar := 0;
SendMessage(wnd, wm_user + 94 {em_gettextex}, integer(@text), integer(txt));
memo1.Text := txt;
FreeMem(txt);
end else begin
ShowMessage('Can''t find a window');
end;
end;
I think that there's something wrong with using em_gettextex in my source. There are no problems with em_gettextlengthex - it gets the right length (I think) ;)
Btw, getting handle was a little tricky for me ;) have never done it this way before.
Btw, getting handle was a little tricky for me ;) have never done it this way before.
ASKER
tricky but realtively fast:-)
about the em_gettextex crash, I hope it is not delibrately done by the client for security purposes.
They have been trying to make programming bots harder. You know they consider it cheating. However mine is a simple calculator not a bot. I prefered dealing with the rich edit where there was another option which is screen scraping. that would be harder imho. I will try to figure it out and will definitely feed you back on this.
thank you
about the em_gettextex crash, I hope it is not delibrately done by the client for security purposes.
They have been trying to make programming bots harder. You know they consider it cheating. However mine is a simple calculator not a bot. I prefered dealing with the rich edit where there was another option which is screen scraping. that would be harder imho. I will try to figure it out and will definitely feed you back on this.
thank you
I don't know, maybe they have written their own message processing and are using wm_user+94 message. When I changed text.codepage from cp_acp to 1200 (from ANSI to UNICODE), program didn't crash, but... It restarted :) Don't know why.
Found a way :)
var
wnd : cardinal;
txt : pchar;
len : integer;
loop, lines : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
GetMem(txt, $ff);
lines := SendMessage(wnd, em_getlinecount, 0, 0);
for loop := 0 to lines - 1 do begin
move(#$ff#$00, txt^, 2);
SendMessage(wnd, em_getline, loop, integer(txt));
Memo1.Lines.Append(trim(tx t));
end;
FreeMem(txt);
end else begin
ShowMessage('Can''t find a window');
end;
end;
var
wnd : cardinal;
txt : pchar;
len : integer;
loop, lines : integer;
begin
wnd := 0;
GetMem(txt, 256);
repeat
wnd := FindWindowEx(0, wnd, '#32770', nil);
GetWindowText(wnd, txt, 256);
len := lstrlen(txt);
if len > 16 then begin
inc(txt, len - 16);
if txt = '. Good Luck ! ' then begin
dec(txt, len - 16);
break;
end;
dec(txt, len - 16);
end;
if lstrcpyn(txt, txt, 7) = 'Table ' then break;
until wnd = 0;
FreeMem(txt);
if wnd <> 0 then begin
wnd := FindWindowEx(wnd, 0, 'RICHEDIT', nil);
GetMem(txt, $ff);
lines := SendMessage(wnd, em_getlinecount, 0, 0);
for loop := 0 to lines - 1 do begin
move(#$ff#$00, txt^, 2);
SendMessage(wnd, em_getline, loop, integer(txt));
Memo1.Lines.Append(trim(tx
end;
FreeMem(txt);
end else begin
ShowMessage('Can''t find a window');
end;
end;
ASKER
man, how can I add more point?:-)
This is working very smoothly. Great job and this thread was a very nice lesson in in api programmin also. I am getting the text now. thank you
This is working very smoothly. Great job and this thread was a very nice lesson in in api programmin also. I am getting the text now. thank you
You can't add points :)
Actually 500 points is also a good "payment" :) Even more - I just answered on your question.
This was "a nice lesson" for me too :) AAArgh! Just love ex-ex because I can learn by answering, heh
Actually 500 points is also a good "payment" :) Even more - I just answered on your question.
This was "a nice lesson" for me too :) AAArgh! Just love ex-ex because I can learn by answering, heh
ASKER
the lesson is not finished yet:-) kidding. everything works great.
I just want to learn more about what you did in the move procedure.
what does this mean GetMem(txt, $ff); ? I mean the $ff
and this move(#$ff#$00, txt^, 2); I mean the #$ff#$00 ?
Should I open a new question for this?
I just want to learn more about what you did in the move procedure.
what does this mean GetMem(txt, $ff); ? I mean the $ff
and this move(#$ff#$00, txt^, 2); I mean the #$ff#$00 ?
Should I open a new question for this?
ASKER
oh ok. found it i think
$ff is 255 and $00 is 0
$ff is 255 and $00 is 0
About FreeMem and GetMem... txt is PChar. It's pointer to memory, so we need to allocate memory to work with it. That's why GetMem is needed. FreeMem frees memory when it's not needed anymore.
move() procedure copies data to specified destination. You may also use MoveMemory() to do this. Why did I do that? MSDN said that it's needed :)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/editcontrols/editcontrolreference/editcontrolmessages/em_getline.asp
Read about lParam parameter.
About #$FF#$00 - that's something like chr(255) + chr(0). If you add $ symbol to some number, you may write it as hexidecimal. If you add # character, it turns to CHAR.
$61 = 97
#97 = #$61 = 'a'
That's if using it with strings.
move() procedure copies data to specified destination. You may also use MoveMemory() to do this. Why did I do that? MSDN said that it's needed :)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/editcontrols/editcontrolreference/editcontrolmessages/em_getline.asp
Read about lParam parameter.
About #$FF#$00 - that's something like chr(255) + chr(0). If you add $ symbol to some number, you may write it as hexidecimal. If you add # character, it turns to CHAR.
$61 = 97
#97 = #$61 = 'a'
That's if using it with strings.