推动视窗的手-- 驱动程式

>>>  名人論史——近當代作家的史學觀點  >>> 簡體     傳統

发表日期 : 1993.06
 

今天我们看看比较冷门的主题,
关於 Windows 的驱动程式。
这种题目非常稀少,找得到就该偷笑了。
由於撰写驱动程式都是以组合语言为之,
所以我顺便谈一谈组合语言。


F301 闹热滚滚,立法院也是闹热滚滚。你有没有注意到,新的着作权法生效後,出国带两本一样的书回来竟然要锒铛入狱,而且不因没有犯意而免其罚。花钱消费也犯法我真是搞不懂。不过不管这次立法合宜与否,注重智慧财产权应该已经是全民共识,尤其身受高级教育的高级知识份子,自己所从事的也是智慧财产的工作,理当感同身受,身体力行。可是许多次向朋友或学生介绍好书的时候,他们的反应竟然是 : 我可不可以向你借来 copy ? 妈妈咪呀,这不单是你触了法,我也有罪的你知道吗 ? 虽然天地你我之外不会再有人知道,但对着也好舞笔弄文的我而言,这样的请求实在是让我很难堪。许多法人机构或略具规模的公司有自己的图书馆,也有专人负责的影列室,常就做这代客拷备之情事,「嗨 Miss 王,请帮我部门拷十本」。

希望藉着这个小园地呼 我的读者,书的确是不便宜没有错,但酒肉穿肠过书香留心中,一本对你有帮助的书,它的价值难道不比二场电影一客牛排吗 ? 听说国人每人每年平均花的买书钱是 120 新台票,实在是有点儿...呵呵。经济能力范围之内我们还是慢慢地养成不要 ㄎㄠ 的习惯吧。这种事勉强不来,但是,慢慢养成吧。请以行动支持你喜欢的作者,你喜欢的杂志,你喜欢的出版社。如果他们熬不下去消失了,大家都损失对不对 ?

闲话就此打住,今天我想为各位谈一谈比较冷门的主题,关於 Windows 的驱动程式。 

背景资料 :
书名 Writing Windows Device Drivers
作者 Daniel A. Norton
出版 Addison Wesley
页数 6 章,434 页
售价 US$ 29.95
磁片 No

1. Introduction
2. Windows Operating Modes
3. GDI-The Graphics Device Interface
4. Printer and Plotter Drivers
5. Display Drivers
6. System Drivers
7. Virtual Device Drivers
8. Virtual Driver Services
9. System Virtual Drivers
10. Nonstandard Device Drivers
11. Driver Installation
Appendix A GDI Structures
Appendix B GDI Driver Entry Points
Appendix C Device Driver Support Functions
Appendix D Standard Mode Grabber Functions
Appendix E System Driver Entry Points
Appendix F VxD Services
Appendix G Japanese Printer Escapes
Appendix H Recommended Reading


从书名上要找一本关於 Windows 驱动程式设计的书,大概这是绝无仅有的了。(Addison Wesley 另有 Writing DOS Device Driver 和 Writing UNIX Device Driver)。其实这本书并不容易阅读,文字多图片少,程式例更是几乎没有,内容又偏冷涩。不过寡占市场下什麽都得忍着点,找得到这种主题的书就该偷笑了。

本书第一章是概括介绍。Windows 之所以成功的理由之一是它的标准化,由於标准化,应用程式可以从 Windows 获得许多高级精巧的特质。虽然 DOS 也提供INT 21h 标准介面,但是照顾面不够广,例如 DOS 没有标准的键盘扫描码,没有标准的序列埠介面,DOS 也没有图形模式下的标准绘图介面(Microsoft C 提供一套图形函式库,Borland C 另有一套;如果你要用标准 BIOS 介面,肯定这个软体不能卖,速度太慢了)。Windows 对这些硬体都有完整的应用程式介面 (API)。

Windows 另一个成功因素是封装化 (encapsulation),再具体一点就是应用程式与硬体的隔离相当彻底。应用程式不必在意安装在系统上的是哪一型态的硬体,於是程式中也就没有关於某特定硬体的码,因而可以在不同的周边硬体上执行。举例来说应用程式要画一个四方形,它不必在意执行对象是 EGA 或是 VGA 或是SuperVGA,或甚至是点榘阵印表机 (雷射印表机也行),用的是同一个函式 Rectangle() :

hDC = GetDC(...); // 输出到萤幕
// hDC = GreateDC(...); 输出到印表机

Rectangle(hDC,...);


关键在於 DC (Device Context),这是一个描述装置特性的资料结构,它的内部由该装置的驱动程式填满。

作者把 Windows 的驱动程式分为四类 :

■ System Driver : 这是完全与 Windows 系统整合在一起的驱动程式,像 display,network,keyboard, COM port、LPT port,mouse,sound 等,也就是你在安装 Windows 时画面上为你侦测的周边设备。这些系统驱动程式所支援的硬体几乎不管什麽环境都会用的上。

■ Printer Driver : Windows 印表机驱动程式的责任是把 bitmap 和 font 资料转换为合适的型式送到所附属的印表机上。送到 HP LaserJet III 的命令码和送到 Epson FX-85 上的命令码并不相同。这些驱动程式应该由印表机制造厂商提供给客户。应用程式完全不管什麽驱动程式,只要依 API 取得DC 即可。回应 API 而提供适当之 DC 内容,正是驱动程式的责任。

■ Virtual Device Driver : 这是与各种真实的驱动程式都不相同的程式与观念。这种 32 位元 Flat Model 程式并不是要为一个实际存在的硬体提供程式介面,而是要以软体模拟一个硬体。为什麽要这麽做 ? 为的是 Intel 80386 提供虚拟机器(VM) 能力 (Windows 386 加强模式可以将之实作出来),而虚拟装置驱动程式可以为每一个虚拟机器模拟一个专属的周边硬体。

■ NonStandard Driver : Microsoft 的驱动程式发展工具 (DDK) 描述的只有上述的所谓标准驱动程式,如果是特殊周边硬体,就属於这种非标准型的驱动程式。

应用程式与硬体隔离最明显的例子就是人机介面 (User Interface) 的设计。Windows 应用程式不需关心实际执行时处於哪一种绘图模式,就可以做出外貌一致(功能当然也是一致) 的功能表单、对话盒。我自己曾在 DOS 环境下开发一个事件驱动 (event driven) 的绘图模式功能表单推动引擎,你知道有多麻烦吗 ? 要针对不同的萤幕解析度计算功能表单的宽高,选用不同的字形(1024x768 模式下使用 16x16 字形会让客户罹患眼睛屈光异常 --- 也就是近视啦),要针对不同的 C 编译器使用不同名称的绘图函式 (所幸 Microsoft C 和 Borland C 的图形函式库以及叁数大致一一对应,利用 #define 就可解决);谢天谢地这些 C 编译器厂商提供的图形函式库已有自动侦测显示卡硬体的能力,而且也提供各种绘图模式的驱动程式,否则应用程式可有的写了。这还没完,为了应付高解析度画面贮存引发对记忆体无底洞似的索求,程式员得有三头六臂去取 Extended 记忆体、Expanded 记忆体、或磁碟空间 (有一些软体公司已设计这一方面的函式库出售,不过合不合你用得试试才知道)。於是我们看到程式员彷佛千手千足观音,而这时候根本还没进入应用程式的主旨呢! 我对 GUI 系统有这麽深刻的爱恋,良有以也,良有以也。

第二章 Windows Operating Modes 介绍很基础而重要的保护模式定址方式,也介绍了线性位址与实体位址的定义与彼此的关系,以及 Windows 的三种执行模式。这个主题在讨论保护模式的书籍中几乎都会提到,无责任书评第四期介绍的Entending DOS 一书就有很多相关内容。

第三章介绍图形介面 GDI (Graphic Device Interface)。GDI 使得应用程式在描述图形资讯以及发出绘图命令时不必在意底层的硬体。GDI 可应用在 display 和 printer 两种驱动程式上,本章所谈的 GDI 是这两种驱动程式的共同部份,至於不同的部份分列於四、五两章。display 驱动程式直接处理硬体,而 printer 驱动程式则是利用 "GDI call" 执行输出,不直接控制硬体。printer 驱动程式甚至於呼叫 display 驱动程式提供的 dmBitBlt 以完成它自己的 BitBlt()。

为了能够将应用程式的 GDI 呼叫翻译为装置驱动程式认识的码,Windows 必须拥有该装置的某些资讯,这资讯就放在 GDIINFO 结构中。你可以利用 GetDeviceCaps() 获得此结构的各栏位资讯。

第四章介绍 printer 驱动程式。篇幅很少,除了获知 GDIINFO 结构中与printer 相关的栏位说明,以及 Windows 的 Printer Manager 扮演的角色,再就是一个 printer 驱动程式所必须提供的 24 个函式 (程式介面)。

第五章介绍 display 驱动程式。这是 Windows 最重要的驱动程式,因为它影响Windows 的整体效率至巨。printer 驱动程式缓慢犹可为 (你可以利用午餐或是午夜印表),display 驱动程式缓慢则简直不可活。它怎麽会这麽忙碌呢 ? 看看下面的说明。每当应用程式呼叫 GDI 函式,Windows 就至少呼叫display 驱动程式一次 (即使是 non-GDI 函式,Windows 也可能呼叫它);就连滑鼠移动,display 驱动程式也要工作 (不然萤幕上的游标怎麽会移动 ?);有时候甚至於整个系统都停顿了,display 驱动程式还不得闲,因为编辑器中的位置指示器 (caret) 一直得闪个不停。

由於 display 驱动程式关系到 Windows 的效率,所以程式员通常无所不用其极地以各种奇险怪招来写它。除了程式码,display 驱动程式比较奇特的是它还内含resource,包括十三个各式各样视窗元件 bitmap (可以 LoadBitmap() 获得);十一个标准的 cursor (可以 LoadCursor() 获得);五个标准的icon (可以 LoadIcon() 获得);一组 display 的预设状态资讯(可以 GetSystemMetrics() 获得);一组颜色表格资讯,其中的颜色在 SDK 手册中的SetSystemColor() 有说明;一组系统库存字形的资讯,包括所谓的 IBM PC-8 字形、Courier 字形和 sans-serif 字形。

上述的最後三种 resource 是所谓的 "raw data resource"。这一章有一小段文字教我们如何制作 "raw data resource" (也就是所谓的 customize resource),可以应用在一般程式以解决记忆体不足的问题。步骤如下 :

1) 以组合语言撰写一个仅有一个资料节区的程式,资料内容就是 customize resource 的二进位码。

2) 组译、联结获得一个 EXE 档。

3) 使用 EXE2BIN 将此 EXE 档的表头去除,获得 BIN 档。

4) 在应用程式的 RC 档中以下列语法描述此 resource :

nameID OEMBIN [load-option] [mem-option] filename

此一技巧应用到一般程式上头,对於具有大型 look-up 表格的应用程式,可以樽节不少 AUTO 节区 (64KB) 空间,因为资料空间从 AUTO 节区的static 区域搬移到 resource 节区去了。实例可以叁考 Microsoft Systems Journal 在 1991/01 由 Paul Yao 发表的文章 : Improve Windows Application Memory Use with Subsegment Allocation and Custom Resources。Yao 在文章中将 0-90 度的正弦值放入一个 ASM 程式的资料节区中并联结为 EXE 档,再转换为 BIN 档 (上述步骤中的 1,2,3) :

; file : sinedata.asm
; masm sinedata.asm;
; link sinedata;
; exe2bin sinedata.exe
SINDATA segment public
DW 0, 175, 349, 523, 698, 872, 1045, 1219
DW ...
SINDATA ends
END


获得 sinedata.bin 後在应用程式的 RC 档中描述 :

#define TABLE 100

SIN TABLE DISCARDABLE sinedata.bin


并且在应用程式中这麽使用 :

HANDLE hRes, hresSinData;
int FAR *fpSin;

hRes=FindResource(hInst,
MAKEINTRESOURCE(SIN),
MAKEINTRESOURCE(TABLE));
hresSinData = LoadResource(hInst,hRes);
fpSin=(int FAR *)LockResource(hresSinData);

//
现在 fpSin 指向 resource 第一笔资料。


UnlockResource(hresSinData);
FreeResource(hresSinData);


Yao 实在是个想像力和创造力非常丰富的人!


具有调色盘经验的程式员一定知道,虽然你选择的绘图模式可同时显现256 个颜色,应用程式却只能使用其中的 236 颜色,有 20 个颜色是保留给系统的。GDIINFO 结构中的 dpPalReserved 栏位值指的就是保留多少颜色作为Windows 系统颜色。这必须是偶数,最少是 20,其中一半放在硬体调色盘的最低记录内,另一半放在硬体调色盘的最高记录内。20 个保留颜色值在本章有一个列表。

和 display 驱动程式搭配的 grabber,肯定许多人不知道是什麽东东。当 Windows 切换至 DOS Session 或是从 DOS Session 切换至 Windows 时,grabber 就用来协助贮存 DOS Session 的视讯模式。它的功能像是一个动态联结函式库,提供许多常式给 non-Windows 应用程式使用,使虚拟机器 (意指 DOS Box) 的萤幕格式成为 Windows display 驱动程式的 bitmap 格式。所以你能够在 Windows 环境中看到 DOS Box 实在是 grabber 的贡献。上述所说的 non-Windows 程式指的是 WINOLDAP.MOD,因为所有 non-Windows 应用程式都由 WINOLDAP.MOD 呼叫Shell device 後执行起来。

Grabber 分为 286 和 386 两种,前者的附属名是 GR2,後者是 GR3。(但在 Windows 3.1 中前者附属档名却是 2GR,後者是 3GR。你瞧 Microsoft 搞的 !)。GR2 的格式像 COM 程式,只在 CPU 真实模式中执行,用於 Windows 真实模式和标准模式中; GR3 的结构像是 Windows 的动态联结函式库,在 CPU 保护模式中执行,用於 Windows 386 加强模式中。务请记住,如果你设计一个 display 驱动程式,也要设计一个对应的 grabber。Microsoft DDK 手册中的 Virtual Device Adaptation Guide 第十八章对 grabber 也有不错的叙述。

本章只涉及 Windows 与 display 驱动程式之间的通讯,列出 display 驱动程式应具备的 export 函式以及 grabber 应具备的函式,但绝口没提像 line drawing 或是pattern fill、font design 等与装置相关的重要设计主题。

第六章介绍 system 驱动程式,这指的是 keyboard, mouse, COM, LPT, sound, local area network 等驱动程式。这些驱动程式都有自己独一无二的Windows 介面,很难以一般性的方式统一讨论它们。

第七章介绍 VxD (虚拟装置驱动程式),也就是 .386 程式。大多数写 DOS 驱动程式的软体人员就是在这里触礁。自从 Intel 80386 问世之後才有所谓的虚拟机器 (Virtual Machine, VM),而自从 Windows 3.x 以及 OS/2 2.0 之後才把虚拟机器完整的实作出来 (过去 GUI 系统的 DOS Box 是以软体模拟完成,并非使用V86 模式)。本章介绍许多重要的观念像 VM、Flat model,不只做为写 VxD 的基础知识,在了解整个 Windows 作业系统乃至於保护模式都很重要。不过我感觉解释的未臻理想,我的意思是文字叙述有点儿重点整理的味道,换句话说你得有底子才看得懂。

本章虽然也介绍 VxD 的程式写法,但全是文字描述。一望无际的文字、文字... 很是令人心浮气燥。哪有人全以文字描述的方式来教写程式的 ? 我一直认为任何书籍的作者都应该知道自己的读者是什麽层次,难道一个初学Windows 的人会看这本书吗 ? 读者是资深 (senior) 工程师的话就不必废话连篇冗言处处,一小段程式码再加注一些说明,最好再有线条箭头标出各函式、节区、变数的来龙去脉,简单明辽又畅快。真要学习 VxD 程式设计,DDK 手册中的 Virtual Device Adaptation Guide 以及稍後要介绍的 Windows 3.1 Developer's Workshop 表现好很多。

关於读者的定位,我另外还有一些意见。不知道大家会不会对中文电脑书籍中的某些中文名词有着某种程度的意义上的隔阂 ? 我想中文书籍不见得一定要全是中文字嘛,一些尚未达成共识的名词就用原文不是顶好 ?! 当然其多寡与安排是必须拿捏的,这有赖作者的文字功力,否则太多中英文夹杂,阅读起来也不会很顺。好作者就是能够让你看硬梆梆的技术文字而不觉佶屈聱牙,舌头打结。我这篇文章的英文名词就太多了些。

上星期我操作 CWindows 3.1 Beta 版的 OLE 功能,表单拉下来迟迟无法下手,因为上面文字的意义对我很陌生。极富意识型态的读者不必写信来扣我民族意识的大帽,我只是指出事实 (当场感觉陌生的人可不只我一个),该怎麽解决我也没有案子。上次在杂志上看到两帮人马笔战 Windows 可能造成的软体侵略,最後又扯到民族意识,怪可怕的。

再回到主题上。第七章介绍的是 VxD 程式的静态结构,第八章介绍的则是 Windows 核心部份之 VxD 提供的 service,这些 service 集中在WIN386.EXE中,包括 Scheduler、Memory Management、VM Trapping、VM Control、Virtual Interrupt、User Shell、Debugging、Miscellaneous 等等。VxD 发展者不但要熟悉欲模拟之硬体性质,也应该要熟悉手上可应用的工具,本章介绍的这些由系统提供的 service 就是各式各样的工具。这些 service 依叁数传递的方式分为两大类 : 藉堆叠传递以及藉暂存器传递。前者也就是所谓的 32 位元 C 语言呼叫惯例,其 service 名称以底线开头,如 _Allocate_Global_V86_Data_Area;後者则直接以英文字母开头,如 Get_Cur_VM_Handle。我为什麽不把 service 直接说是「服务」或是「函式」呢 ? 因为 service 有它特别的意义 : 给 VxD 呼叫的常式码称为 service (另一种给一般应用程式呼叫的函式称为 API)。

虽然 service 是给 VxD 呼叫,API 才是给一般应用程式呼叫,但总是有一些天才会想出一些很正点的歪点子。Andrew Schulman 在 MSJ 1993/02 就以一篇Call VxD Functions and VMM Services Easily Using Our Generic VxD 向世人昭告他是点子族的个中翘楚。这篇文章提供一个 VxD.386,允许你在 C 程式中直接呼叫由 VMM 提供的 service,这些 service 可不是那种头上长角的奇怪程式才用的着。如果你有新鲜构想,恰恰又有 VMM 的 service 可以支援你,做出来的软体将是非常不一样。你可曾希望从 Windows 程式中传送键盘按键 (keystroke) 到一个 DOS box ? 利用 PostMessage() 送 WM_CHAR 或 WM_KEYDOWN 到 DOS box 的视窗 handle 可以勉一为之;但如果 DOS box 是全萤幕而非视窗型式,这就行不通。这时候呼叫 DDK 的 VKD_Force_Keys 可以解决。你想要真正享受 Windows 的强制性 (preemptive) 多工吗 ? SDK 对此完全没有描述,但在 DDK 中相关 service 塞满一牛车,如 Schedule_VM_Event、Begin_Nest_Exec、Exec_Int、Simulate_Far_Call,这些都是 Windows 程式在与其他 VM 沟通时所需要的。

前述 Schulman 设计的 Generic VxD 提供了一个 API,能够让「在 Windows 386 加强模式中执行的程式 (包括 MD-DOS box 中的程式)」呼叫任何一个 VMM service。应用程式只要指定要呼叫的函式名称以及叁数即可。使用这个 API 就像使用 C 函式库的 int86x() 函式一样。设计上的第一个问题是如何能够明确告诉 Generic VxD 我们要呼叫哪一个函式。幸运的是每一个 VMM service 都有一个相关的识别码 (是个 DWORD) 以及相关的函式编号,所以这问题不难解决。接下来呼叫者需要一个方法来指定叁数以及放在暂存器中的回返值。Generic VxD 制造一个暂存器影像 (register image,你想像是个暂存器的副本好了),这和使用於 int86x() 的 REGS 和 SREGS 结构有异曲同工之妙。但并不是每一个 VxD 都期望叁数放在 32 位元暂存器中,许多 service 是从堆叠中取叁数,并使用 C 的呼叫惯例(calling convention)。这一点必须考虑在内。

程式呼叫 Generic VxD 时只要传递函式号码,(例如 0x010001L 代表 Get_Cur_VM_Handle,0x0D0007L 代表 VKD_Force_Keys),这号码会被转换为真正的 service 名称。如果你详细看看 DDK 的 VMM.INC 中的 VxDCall 巨集定义,你将发现事实上 VxDCall 是一个 INT20h,後面跟着一个 DWORD (放 service 号码)。所以 "VxDCall VKD_Force_Keys" 只不过是 "INT20h 0D0007h" 比较漂亮的表达方式而已。这就是 Generic VxD 的设计与运作,它只是模拟组译时期的 VxDCall 巨集,让它在 run-time 执行而已。Generic VxD 只不过是个转换机制。

Andrew Schulman 实在是个想像力极为丰富的人,他也曾设计一个名为 WINIO 的函式库,把一般的 C 程式转换为 Windows 程式,这在无责任书评第三篇介绍Undocumented Windows 一书时提过。

第九章介绍系统所属的虚拟装置驱动程式。考虑一个 VxD 应该从两个观点,它既是service 的供应者也可能是 service 的呼叫者。所以如果你要自行设计一个 VxD 取代现存的 VxD,一定要顾虑到这两点,务必让介面保持原封不动,以免影响相容性。本章介绍的三个 VxD 是 VDD、VKD 和 VCD (分别是显示器、键盘和通讯)。

第十章介绍非标准的装置驱动程式,像数位笔、扫描器。DDK 并没有提供这一类程式例,所以做起来自我摸索就辛苦一些。这种驱动程式可以以下列数种型式呈现 :

■ 标准的 DOS 驱动程式。

■ DOS 常驻程式。

■ Windows 应用程式。

■ Windows 动态联结函式库。这麽做的好处是呼叫时不需要切换到 CPU 真实模式(286 保护模式要切换到真实模式,必须 Reset,那是很慢很慢的动作。386 保护模式无此困扰)。

■ Windows 虚拟装置驱动程式。缺点是它所提供的介面不够高级,应用程式获得的是以 INT 2Fh 得到的 entry point (相当於函式指标),而不能够直接呼叫函式名称并传递叁数。

到底选哪一种,要看使用此驱动程式之应用程式的型态,以及它所期望的介面。

总括来说,本书的内容令人有踩在云端的感觉,都是政策性的宣示而没有政务性的实作。虽然探讨系统内部的观念颇为难得,但对於想从中学习 Windows 驱动程式实际写作的人而言,目的地距离出发点恐怕很遥远。一本书之受到注意,有三个因素 : 一是主题选得好 (要不很热门,要不很稀有),二是作者很有名气 (书的品质有一定口碑),三是书籍内容的整理、编排、文笔都下过一番功夫。本书只能归为第一类。譬如介绍 32 位元程式的虚拟装置驱动程式,第一个闪过我脑子的念头是我该用哪一种工具制作它 ? 本书没有在适当时机解我疑惑,纵观全文也只说需要一个 80386 组译器 (这可不是白说吗 ?)。全书的组织架构不能算是佳作。不过当你愈来愈深入到系统内部,会发现自己愈是高处不胜寒,想买书嘛没书买,想找人讨论也不知良人何处。不过单就主题而言,我个人仍觉得这是一本难得的书。

作者在书本一开始的致谢部份谢谢所有在 CompuServe 的 Forum (论坛) 上向他发问并鼓励他找出答案的人,以及在论坛中回答他的问题的人。同时也提到本书实际上并没有关於装置驱动程式的程式设计方法,要发展真正驱动程式的软体人员应该上论坛去多与人请教讨论。我不知道国内上 CompuServe 的公司或个人有多少,这真的是个大大的资源,值得好好利用,不过别玩昏头了。我的朋友每天花半个上班天看信回信,这会上瘾的。当然,你想想看与全世界同好在网路上沟通,还不兴奋吗 ?! (编按 : 关於 CompuServe 及国际网路,请叁考附录 A)

我过去介绍书籍从不曾把附录列出来过 (其实附录也有可观之处),这本书特别列出来实在是因为附录 A 从 191 页就开始了 (全书 434 页) ,整个附录占篇幅的 1/2 强,不能不表。

背景资料 :
书名 Windows 3.1 Developer's Workshop
作者 Dr. John Bulter,
Bob Chiverton,
John Clark Craig,
William S. Hall,
Ray Patch,
Alok Sinha
出版 Microsoft Press
页数 6 章,322 页
售价 US$ 34.95
磁片 Yes

1. Internationalizing Windows Software
2. Zooming, Coordinate Spaces, and Transformations : From Win16 to Win32
3. Programming Windows for Pen Computing
4. NetBIOS Programming
5. Developing Virtual Device Drivers
6. Visual Basic as a Professional Tool


这本书有点儿论文集的味道,六位作者各自负责一个主题。我要特别介绍的是第五个单元 : Developing Virtual Device Drivers。作者 Ray Patch 的组织能力相当不错,看下来的感觉是「两岸猿声啼不住,轻舟已过万重山」,爽快。你觉得一本书最重要的是什麽 ? 组织能力或是文笔。我比较注重前者。当然如果再搭配一支生花妙笔肯定会是畅销书。不过在技术性书籍而言那也不一定,还得看主题是什麽。不信你就写一本,嗯...Macintosh 程式设计,看看在台湾卖几本。

这个单元所叙述的 VxD 程式设计,明显比上一本 Writing Windows Device Driver 第七章实在的多,对於 VxD 的宣告部份、每一个宣告叁数所构成的 DDB 结构 (关系到 VxD 的介面)、以及 VxD 程式进入点中处理的讯息和处理方式、乃至於 VxD 与应用程式之间的叁数传递挢梁 CRS (Client Register Structure,由 ebp 所指的一块区域),都介绍得十分清楚。对於 VxD 中的 Service 或是 API 的写法,也都有实例解说。当然,如何呼叫 VxD (不管是 API 或是 service) 也是重要题目,这些都以十分简洁有力的方式描述,毫不拖泥带水。本单元最後并附一个程式骨干,有 VxD 程式的完整格式,只是尚缺乏 API 的设计。Microsoft Systems Journal 在 1992/10 有一篇 Go Anywhere and Do Anything with 32-bit Virtual Device Drivers for Windows,其中有一个小程式 CR3.386,恰恰与本章相反,只有 API 设计而无 service。两者天残地缺互相搭配,perfect !

依我的看法,要教读者 VxD 程式写法,最佳方式莫过先给一个所谓的程式样板 (template),让读者先大致了解这种程式的架构空壳 (VxD 有固定的格式),脑袋中有了整体概念,再开始细项介绍,才最是理想。这就好像程式设计中的 top-down 方式。然而绝大多数的书籍,都是采用落伍的 button-up,让你管中窥豹胡兜半天,才兜起一个程式。我不认为这是好方法。也许对付这种写法的书籍,就是先翻到後面看看实际的程式。但这是不一样的,我说的是把整个精髓保留下来的程式「骨干」,不是要看一个长达数百行的完整程式。一个好作者,应该能够设身处地为读者想 : 现在,他要的是什麽。

 

背景资料 :
书名 Power Programming with Microsoft Macro Assembler
作者 Ray Duncan
出版 Microsoft Press
页数 14 章,370 页
售价 US$ 39.95
磁片 Yes

1. Thoroughly Modular MASM
2. Processing Command Lines
3. Using the Environment
4. Converting Numbers for Input and Output
5. Manipulating Strings
6. Times and Dates
7. Sorting Numbers and Strings
8. Using the MS-DOS File System
9. Sequential Files
10. Random Access Files
11. Heaps, Lists, and Binary Trees
12. Multiple-Precision Integer Arithmetic
13. Using the Intel Numeric Coprocessors
14. Optimizing Assembly-language Programs


masm.jpg (16808 bytes)


上一期无责任书评最後一页有一个 sidebar (与正文有关的花边新闻) (编按) : 组合语言细说从头,以半页篇幅介绍三本组合语言书籍。本书就是其中之一。由於撰写驱动程式都是以组合语言为之,所以我顺便来谈一谈这本书。(编按: 侯捷指的是微电脑传真杂志上的 sidebar)。

作者 Ray Duncan 在 PC Magazine 主持一个 [Power Programming] 专栏,本书的几个主题是他在专栏中发表的内容收录集合下来的。这不是一本组合语言入门书,关於组合语言的指令以及 MASM 组译器的基础介绍并不多。只有第一章对於档案模组与程式节区之间的关系,以及程式节区与节区暂存器之间的关系有一些描述,再就是针对 Microsoft MASM 新版本的新特性 (如资料结构,高阶语言介面,新的 directive) 做一介绍。第二章开始是以应用实例为导向,分别介绍如何处理命令列叁数、环境变数、文数字与数值之间的转换、字串的处理 (如字串比较、字串并合、寻找特定字元 ...)、时间与日期的处理 (ASCII 字串与真正二进位时间日期数值的转换)、字串与数值的排序、基本档案操作、循序档的操作,随机档的操作、记忆体 (heap) 配置,资料结构中的串列 (link-list) 与二元树的实作、倍精度整数运算、浮点数运算。最後一章是作者浸淫组合语言的心得力作 : 如何将组合语言程式最佳化,包括大小与速度。

书中所有程式码都放在随书所附的磁片中。这些函式虽然不错,不过在 C 函式库的效率也相当好的今天,它们的实用性就没有那麽重要了。我看了一下定价,台币 1200.0,委实太贵。是因为作者的名气吗 ?

我曾半开玩笑说写组合语言的人是稀有动物,也有朋友半开玩笑表示抗议。不知道抗议缘由为何,物以稀为贵不好吗 ? 组合语言的重要性我就套用该 sidebar 上的一小段文字好了 :「在图形介面充斥的今天,组合语言仍有其相当地位。占程式总体比例不高,但是地位关键;攸关性能好坏,是了解电脑的基础;可以与晶片并肩合作,是控制电脑的最佳方式」。

不过即使你手上有一把好锤子,也不必看到什麽就想要钉下去。笨重的大锤一钉子下去虽然入木三分,舞起来却辛苦得紧。组合语言用起来委实吃力些。
 


侯捷 2010-07-15 08:32:57

[新一篇] 資訊世界的另一扇窗-- 雜志

[舊一篇] 美麗的電腦新世界-- 多媒體
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表