读取屏幕信息(111分)

  • 主题发起人 主题发起人 LuckyGrass
  • 开始时间 开始时间
L

LuckyGrass

Unregistered / Unconfirmed
GUEST, unregistred user!
在WINDOWS环境下,如何用DELPHI编程来读取屏幕上一块区域的信息?
 
可以的,
var
aCanvas: TCanvas;
DC: HDC;
begin
DC := GetDC(0);
// 得到桌面的设备环境句柄,
aCanvas := TCanvs.Create;
aCanvas.Handle := DC;
// 其中 aCanvas 的内容就是整个桌面的内容,
//你可以作任何事,textout, copyrect ......
ReleaseDC(0, DC);
aCanvas.Free;
end;
 
用“鼠标钩子”或“定时器”得到鼠标的位置,如果鼠标移动了,那么在鼠标
位置下放置一个很小的窗口,(在我的程序中此窗口高度为1,长度为1,小得
象针尖一样)windows系统会发出WM_PAINT消息,指示IE,NETSCAPE等应用程
序重绘屏幕,在IE,NETSCAPE等应用程序响应WM_PAINT时,会调用TextOut(),ExtTextOut()等API函数来绘制TEXT,如果我们在IE,NETSCAPE等应用程序
的堆栈中拦截到TextOut(),ExtTextOut()的参数,就实现了“屏幕抓字”。
 
我看到一边文章:对每个设备上下文(DC)做一分Copy,并跟踪所有修改上下文
(DC)的操作,这种方法更强大,但兼容性不好实际上,无论那种方法,都有潜在的
问题,如第一种方法,它在WIN95下时仍是16位方式的(32位技术困难较大),这样
就隐含了一个假定:所有文本输出的32位API都要通过16位的DLL实现,在WIN95
中的确如此,担高版本就难说了.而且即使是第一种方法也容易带来兼容性的
问题,比如博雅和中文之星2.0之间就有一定的兼容性问题(WIN95下).
今天做了一个实验,终于大致明白它是怎么实现的。实验很简单,自己写个程
序,在OnPaint()里写一句MessageBeep(-1);让PC喇叭发声。然后运行这个程
序和“金山词霸”(“博雅”也一样下面以“词霸”为例),当鼠标在自己程
序的窗口上停下一会儿(就是取词的等待时间)之后,PC喇叭就会发声,同时
鼠标也会闪一下。
这说明,鼠标停下之后窗口会重画,这必然是“金山词霸”引起的。其目的是
好让这个窗口产生API调用,以截取TextOut()、DrawText()等函数。这样“词
霸”就可以获取该窗口中输出的字符串了,然后再根据鼠标位置作判断,就可
以得到鼠标所指的字符(单词)了。另外,我还不明白的是该如何截取API调
用呢?(这项技术很有用的。)
GetProcAddress()之后应该用自己的函数取代它,然后再调用原来的吧。可是怎么实现呢?
偶认为象博雅这样的取词是通过截获系统DLL(可能是GDI)中的TextOut或其相关函数来实现的.系统DLL内存地址>
 
屏幕抓字技术揭密
----------深入WINDOWS内部探险手记
郑州 马飞涛
一 公开它!
四通利方和金山词霸的用户都曾见识过屏幕抓字技术,鼠标指哪就翻译哪个单
词,这个技术看似简单,其实在WINDOWS系统中实现却是非常复杂和有趣的。 经过
半年多的艰辛探索,笔者终于破解了其中的秘密,并在今天决定公开它,这个人人
都曾见过但是却鲜有人知的秘密,这个只被几家软件公司垄断从未在公开的报刊资
料披露过只言片语的秘密!
回想这半年多的探索,其中浸润了多少笔者的苦闷与欢乐,绝望与兴奋,挫折
与收获,现在都终于有了结果:将屏幕抓字技术的秘密公开,献给孜孜不倦辛勤工
作的程序员们。如果这样做能为国产软件事业的发展效微薄之力,对笔者来说,也
是一桩快事!
二 初识屏幕抓字
最初知道屏幕抓字, 是在购买了〖英汉通〗软件之后。 当时笔者还只是一个
VISUAL BASIC 的初学者, 对 WINDOWS 系统内部的知识了解并不多, 认为在
WINDOWS系统中屏幕抓字的实现应该和DOS系统中的一样,调用一个DOS 中断取屏幕
上的字符或直接读显示内存的内容就可以了。
三 看似很简单,其实不然
随着对WINDOWS系统的认识不断深入,才发现问题并不象想得那么简单。首先,
翻阅了WINODWS应用程序接口(API)中的上千个函数,并没有发现有一个现成的类
似于getWordFromPoint()的函数;根据使用经验,经过判断发现屏幕抓字采用的也
不是图像识别技术;翻阅了SDK的联机文档中没有,DDK的联机文档中也没有;显示
卡编程接口的资料则很难获得,有的也只是CGA到VGA显存的基本知识。回想当时坐
在机子前,面对一屏屏的联机资料(如果是纸,将堆积如山),感觉就是在黑暗中
的大海里航行,没有方向,没有灯光,但强烈的兴趣紧抓着我,一定要把这个谜解
开。
四 选择合适的编程工具
突然又有了一些新的想法:
可否试着截获WINDOWS中关于字符的消息呢?
DC(设备描述表)到底是什么?
WINDOWS的TextOut函数是否将TEXT放在DC的某个单元中?
显然,用VISUAL BASIC就力不从心了。在DOS中用TURBO C编程笔者还算熟练,
因此先尝试用VISUAL C++,但是奇慢的编译速度使人难以忍受, 高度抽象的类让
人一头雾水,开发商务软件可能还行,但开发这样一个深入WINDOWS 内部的系统软
件,望着一堆缠绕不清的类和消息,真有点牛刀宰鸡、刺刀耕田的感觉。
最后选择了DELPHI,第一印象是编译速度真快,在我的祖父型386 机子上编
译一个WINDOWS程序,速度和用TURBO
C的速度感觉差不多,真让人兴奋得爱不释手。
随着不断使用,发觉DELPHI真是一个好的快速开发工具,(快速并不意味着简单粗
糙,而是和WINDOWS系统有混然一体良好接口的表现)让初学者也很容易上手。 调
用各种WINDOWS 函数(包括很多未公开的函数)都非常直接迅速,用它来作开发工
具,大有刺刀见红、一剑封喉的痛快感觉。
五 山穷水尽疑无路
随着对WINDOWS系统了解的深入,我逐渐明白了在向屏幕输出文字时,WINDOWS
系统仅仅只是对某个应用程序发送WM_PAINT消息,告诉该应用程序窗口用户区已经
“无效”而需要重画。具体的“绘制”工作(选择字体,颜色,文字)由应用程序
完成。
应用程序在处理WM_PAINT消息时,调用begin
Paint和EndPaint来获得和释放设
备描述表,调用DrawText、ExtTextOut、 TextOut等函数在设备描述表中“绘制”
文字。
应用程序“绘制”文字, 就象学生(应用程序)奉命(获得 WM_PAINT消息)
用老师(WINDOWS)提供的画笔(DrawText ExtTextOut TextOut等) 在黑板上画画
一样,虽然大家能看到画的是什么字,但是画笔作为绘图工具并不知道画的是什么。
老师(WINDOWS)不知道学生(应用程序)到底用什么字体,颜色,画哪些文字。
   总之 ,WINDOWS并不知道应用程序“绘制”的是什么。“文字”对 WINDOWS
来说只是画笔留在黑板(屏幕)上的粉笔印,只是绘画的痕迹。“文字”只存在于
应用程序的模块中,对WINDOWS系统是“不可见”的。
到处走投无路,真想掂5000块钱,跑到“英汉通”公司买回这个秘密。仔细一
想,钱太少,就是多掂10倍,人家也不一定说。
六 柳暗花明又一村
经过再三考虑,我联想到在DOS系统中编程,会采取改变中断向量地址, 设置
新的中断向量的技术:如果系统调用这个中断,就会先进入新的中断服务程序,然
后再调用原来的中断服务程序。
那末,在WINDOWS系统中也采取这种技术,使系统如果调用某个函数, 先进入
一个跟踪函数,取得原函数的参数,再调用原来的函数。听起来是否象病毒传染和
发作?其实很多程序都采用过类似技术。大学毕业设计声卡时我就用过。
至此, 我认识到应该放弃常规的思路, 采取一些技巧, 截获 TextOut 、
ExtTextOut等函数,使之转向我的跟踪函数,在此查看应用程序(学生)的堆栈中
传递给画笔(TextOut、ExtTextOut等函数)的参数, 从而获得应用程序要在屏幕
上写的“文字”。
七 “ 屏幕抓字”的实现
1 用SetWindowsHookEx()安装鼠标钩子MouseProc;
2 在屏幕上移动鼠标时,系统就会调用鼠标钩子MouseProc;
3 进入MouseProc,获得鼠标的坐标(x,y),
设置对TextOut()、ExtTextOut()等的跟踪程序,
用invalidateRect()告诉系统该点(x,y)“失效”;

系统发出WM_PAINT消息,指示该点(x,y)处的应用程序重绘“失效”的区域。
5 负责绘制该点()的应用程序在受到 WM_PAINT 消息后, 就有机会调用
TextOut()、 ExtTextOut()等函数。
6 调用的函数被拦截进入跟踪程序:设置好了的跟踪程序截获了该次调用,从
应用程序的堆栈中取出 该点(x,y)“文字”的指针;
7 从应用程序的数据段中将“文字”指针的内容取出,即完成了一次“屏幕抓
字”;
8 退出跟踪程序,返回到鼠标钩子MouseProc;
9 在MouseProc中解除对TextOut() ExtTextOut()的跟踪;
10 退出MouseProc鼠标钩子程序,控制权交给系统。
11 在屏幕上移动鼠标,开始下一次“屏幕抓字”,返回步骤2。
八 前景展望
掌握了“屏幕抓字”的技术秘密,稍加改变,我们就可对WINDOWS 系统中的
任意一个函数调用进行动态地拦截、跟踪、修改和恢复,就可让WINDOWS 系统中的
任意一个函数按我们的设想工作,就可构造自己的外挂汉字平台,设计改变字体的
放大镜、改变颜色的变色镜,保护视力的软件视保屏等等。
忘了是哪个bbs上的了。
 
"一块区域的信息"是什么意思?单纯指图象吗?
 
"一块区域的信息"既可指图象,也可指文字。能将图象分解成文字等信息那就太好了。
 
图象好办,就是我说的方法,
文字就不行了,(如果只是单单得到的话)
 
<font color=red>简单可行的方法(已调试通过)</font>:
先在你的窗口上放一个image和一个button,在button的onclick事件中加入:
ScreenCap(0,0,200,100);//左,上,右,下
就截取了屏幕的一个矩形区域(100*200),下面是ScreeCap自定义过程:

procedure TForm1.ScreenCap(LeftPos,TopPos,RightPos,BottomPos:integer);
var
RectWidth,RectHeight:integer;
SourceDC,DestDC,Bhandle:integer;
Bitmap:TBitmap;
begin
RectWidth:=RightPos-LeftPos;
RectHeight:=BottomPos-TopPos;
SourceDC:=CreateDC('DISPLAY','','',nil);
DestDC:=CreateCompatibleDC(SourceDC);
Bhandle:=CreateCompatibleBitmap(SourceDC,RectWidth,RectHeight);
SelectObject(DestDC,Bhandle);
BitBlt(DestDC,0,0,RectWidth,RectHeight,SourceDC,LeftPos,TopPos,SRCCOPY);
Bitmap:=TBitmap.Create;
Bitmap.Handle:=BHandle;
image1.Picture.Bitmap.Assign(bitmap);
Bitmap.Free;
DeleteDC(DestDC);
ReleaseDC(Bhandle,SourceDC);
end;
 
我有问题,50个大洋(自己不多了)!

谁知道屏幕上的数据存在显存的啥地方(95下)?
--够硬的问题吧!
 
多人接受答案了。
 
API HOOK、屏幕取词的完整解决方案见我的《delphi深入windows核心编程》一书,
解决了IE、win98下的高技术难题,支持windows98/2000/xp,
我的主页http://wenjinshan.yeah.net
 
后退
顶部