发信人: tony_tang() 
整理人: wenbobo(2002-12-06 23:12:58), 站内信件
 | 
 
 
屏幕抓字技术揭密 
        -深入WINDOWS内部探险手记 
 一 公开它! 
 四通利方和金山词霸的用户都曾见识过屏幕抓字技术,鼠标指哪就翻译哪个单词 
 ,这个技术看似简单,其实在WINDOWS系统中实现却是非常复杂和有趣的。 经过 
 半年多的艰辛探索,笔者终于破解了其中的秘密,并在今天决定公开它,这个人 
 人都曾见过但是却鲜有人知的秘密,这个只被几家软件公司垄断从未在公开的报 
 刊资料披露过只言片语的秘密! 
 回想这半年多的探索,其中浸润了多少笔者的苦闷与欢乐,绝望与兴奋,挫折与 
 收获,现在都终于有了结果:将屏幕抓字技术的秘密公开,献给孜孜不倦辛勤工 
 作的程序员们。如果这样做能为国产软件事业的发展效微薄之力,对笔者来说, 
 也是一桩快事! 
 二 初识屏幕抓字 
 最初知道屏幕抓字, 是在购买了〖英汉通〗软件之后。 当时笔者还只是一个VI 
 SUAL BASIC 的初学者, 对 WINDOWS 系统内部的知识了解并不多, 认为在WIND 
 OWS系统中屏幕抓字的实现应该和DOS系统中的一样,调用一个DOS 中断取屏幕上 
 的字符或直接读显示内存的内容就可以了。
 三 看似很简单,其实不然随着对WINDOWS系统的认识不断深入,才发现问题并不 
 象想得那么简单。首先,阅了WINODWS应用程序接口(API)中的上千个函数,并 
 没有发现有一个现成的类似于getWordFromPoint()的函数;根据使用经验,经过 
 判断发现屏幕抓字采用的也不是图像识别技术;翻阅了SDK的联机文档中没有,D 
 DK的联机文档中也没有;显示卡编程接口的资料则很难获得,有的也只是CGA到V 
 GA显存的基本知识。回想当时坐在机子前,面对一屏屏的联机资料(如果是纸, 
 将堆积如山),感觉就是在黑暗中的大海里航行,没有方向,没有灯光,但强烈 
 的兴趣紧抓着我,一定要把这个谜解开。 
 四 选择合适的编程工具 
 突然又有了一些新的想法:可否试着截获WINDOWS中关于字符的消息呢?DC(设备 
 描述表)到底是什么?WINDOWS的TextOut函数是否将TEXT放在DC的某个单元中? 
 显然,用VISUAL BASIC就力不从心了。在DOS中用TURBO C编程笔者还算熟练,因 
 此先尝试用VISUAL C++,但是奇慢的编译速度使人难以忍受, 高度抽象的类让雾 
 水,开发商务软件可能还行,但开发这样一个深入WINDOWS 内部的系统软件,望 
 着一堆缠绕不清的类和消息,真有点牛刀宰鸡、刺刀耕田的感觉。 最后选择了D 
 ELPHI,第一印象是编译速度真快,在我的祖父型386 机子上编 译一个WINDOWS程 
 序,速度和用TURBO C的速度感觉差不多,真让人兴奋得爱不释手。随着不断使用 
 ,发觉DELPHI真是一个好的快速开发工具,(快速并不意味着简单粗糙,而是和 
 WINDOWS系统有混然一体良好接口的表现)让初学者也很容易上手。 调 用各种W 
 INDOWS 函数(包括很多未公开的函数)都非常直接迅速,用它来作开发工 具, 
 大有刺刀见红、一剑封喉的痛快感觉。 
 
 五 山穷水尽疑无路 
 
 随着对WINDOWS系统了解的深入,我逐渐明白了在向屏幕输出文字时,WINDOWS 系 统仅仅只是对某个应用程序发送WM_PAINT消息,告诉该应用程序窗口用户区已经 “无效”而需要重画。具体的“绘制”工作(选择字体,颜色,文字)由应用程 序完成。 应用程序在处理WM_PAINT消息时,调用BeginPaint和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)“失效”; 
 4 系统发出WM_PAINT消息,指示该点(x,y)处的应用程序重绘“失效”的区域。 
 5 负责绘制该点()的应用程序在受到 WM_PAINT 消息后, 就有机会调用 Tex tOut()、 ExtTextOut()等函数。 
 6 调用的函数被拦截进入跟踪程序:设置好了的跟踪程序截获了该次调用,从应 用程序的堆栈中取出 该点(x,y)“文字”的指针; 
 7 从应用程序的数据段中将“文字”指针的内容取出,即完成了一次“屏幕抓  字”; 
 8 退出跟踪程序,返回到鼠标钩子MouseProc; 
 9 在MouseProc中解除对TextOut() ExtTextOut()的跟踪; 
 10 退出MouseProc鼠标钩子程序,控制权交给系统。 
 11 在屏幕上移动鼠标,开始下一次“屏幕抓字”,返回步骤2。 
 八 前景展望 
 掌握了“屏幕抓字”的技术秘密,稍加改变,我们就可对WINDOWS 系统中的任意 一个函数调用进行动态地拦截、跟踪、修改和恢复,就可让WINDOWS 系统中的任 意一个函数按我们的设想工作,就可构造自己的外挂汉字平台,设计改变字体的 放大镜、改变颜色的变色镜,保护视力的软件视保屏等等。 
 九 后记 
 希望此文能抛砖引玉,为大家编程时能找到捷径,开拓出新的思路; 对拦截、跟 踪感兴趣的朋友也请来信交流切磋.
 
 
 -- ※ 修改:.tony_tang 于 Sep  8 19:44:00 修改本文.[FROM: 202.96.155.44] ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.155.44]
  | 
 
 
 |