这是一本经典的Windows核心编程指南,从第1版到第5版,引领着数十万程序员走入Windows开发阵营,培养了大批精英。
作为Windows开发人员的必备参考,本书是为打算理解Windows的C和C++程序员精心设计的。第5版全面覆盖Windows XP,Windows Vista和Windows Server 2008中的170个新增函数和Windows特性。书中还讲解了Windows系统如何使用这些特性,我们开发的应用程序又如何充分使用这些特性,如何自行创建新的特性。
玉不琢,不成器
--《Windows核心编程(第5版)》出版前言
在刚刚过去的第29届奥运会上,气势恢弘、美轮美奂的开幕式,精彩纷呈、欢呼不断的赛场,让我们度过了多少个激动人心的不眠之夜!开幕式上,以宏伟气势演绎的各种形式的"和"给人留下深刻的印象,同时也凸现了我们这个时代的主旋律。是的,"事成于和睦,力生于团结。"电影《赤壁》中,饰演周瑜的梁朝伟同样也以一个简单的动作强调了"和"的重要作用。
值此《Windows核心编程(第5版)》出版之际,心里也同样洋溢着一样的情结。作为此书的出版者,我们得到了很多方面的支持,从拿到选题、遴选译者,再到后期的反复审稿,来自社内领导和同仁,来自兄弟出版社,来自微软公司,来自译者,来自读者的支持和热情,大大增强了我们出好书,出精品书的信心和决心,能得到这么多的支持和关注,实乃三生有幸!在此特别向各位表示由衷的感谢!
正所谓"玉不琢,不成器",一本经典著作,不仅要内容精确,还少不了版式和其他细节的精心雕琢与编排。
* 优秀译者是高品质译著的源泉 甄选译者的时候,很多读者朋友踊跃报名,他们都希望能参与此书的工作,为Windows编程领域作出贡献。在此,向他们表示由衷的感谢。他们当中,有70后的资深程序员,也有80后的高手程序员,更有朝气蓬勃的在校学生。考虑到质量和时间的因素,最后确定由微软中国研发集团服务器及开发工具事业部的葛子昂主译,周靖和廖敏参与。优秀译者是高品质译著的源泉,这一点在本书上得以充分的验证。他们在翻译过程中,秉承一贯的严谨风格,在字里行间进行认真的推敲,并认真对代码进行了相应的调试和实践。葛子昂作为主译,不仅精心规划进度,还牺牲了休息时间主动承担了大部分工作,责无旁贷地对全书进行统稿,他对本书的认真程度,让人钦佩。兄弟出版社朋友对本书翻译的参与,也使我大受鼓舞。从他们身上,能够深切地体会到他们的敬业精神,他们是真正的爱书人,全心全意为读者着想的人。为读者奉献更丰盛的技术图书盛宴,促进技术图书的健康发展,这是我们共同的心愿。
* 来自微软的支持 本书由微软中国区微软最有价值专家(Most Valuable Professional,MVP)集体审阅,他们对本书给与高度评价,在此感谢刘彦博、蒋晟和王涛为代表的Microsoft MVP。他们是一群令人敬佩的人,他们具备一种或多种微软技术专业知识,积极参与在线或离线的社群活动,经常与其他专业人士分享知识和专业技能。他们平易近人,是受人尊敬和信任的专家。在全球90多个国家,这样的MVP有近4000名。目前中国区就有215名。
* 大人物的推荐序 本书由Windows Internals(深入解析Windows操作系统)作者提笔所写,他对本书的内容和结构给予了充分的肯定。
* 精美、雅致的版式 在版式设计方面,我们突破技术类图书的常规,精心设计了页眉和章首页,为读者提供更赏心悦目的阅读感受。
* Jeffrey照片和亲笔签名 Microsoft Press的陈帮我们穿针引线,引入Jeffrey的"大头照"、家庭照和亲笔签名,这些都会在书中呈现出来。此外,Jeffrey还计划在2009年4月访问中国,届时欢迎读者朋友参与他的见面会,与他一起探讨和体验Windows编程乐趣。
* 索引 为方便读者查阅,我们在译文相应部分添加了原书页码,同时保留原书索引,并将其附于书后。
* 读后感分享 对于一本好书,很多读者都有自己的心得和感想,并希望和同道中人切磋,这一点,我们将成立一个专门的书友会,读者可以在其中畅所欲言,在《Windows核心编程》书友会这个大家庭中共同成长。详情请关注我社网站首页上的公告。
作为出版工作者,我们要感谢来自译者和读者的支持和鼓励,没有他们,就没有佳作的诞生。关于本书的任何意见和建议,欢迎发送邮件到wenkq@tup.tsinghua.edu.cn,我们一直在聆听大家的心声。
清华大学出版社
目 录
第I部分 必 备 知 识
第1章 错误处理3
1.1 定义自己的错误代码7
1.2 ErrorShow示例程序7
第2章 字符和字符串处理10
2.1 字符编码11
2.2 ANSI字符和Unicode字符
与字符串数据类型12
2.3 Windows中的Unicode函数
和ANSI函数14
2.4 C运行库中的Unicode函数
和ANSI函数16
2.5 C运行库中的安全字符串函数17
2.5.1 初识新的安全字符串函数18
2.5.2 在处理字符串时如何获得
更多控制21
2.5.3 Windows字符串函数23
2.6 为何要用Unicode24
2.7 推荐的字符和字符串处理方式25
2.8 Unicode与ANSI字符串转换26
2.8.1 导出ANSI和Unicode DLL
函数28
2.8.2 判断文本是ANSI还是
Unicode29
第3章 内核对象32
3.1 何为内核对象32
3.1.1 使用计数34
3.1.2 内核对象的安全性34
3.2 进程内核对象句柄表36
3.2.1 创建一个内核对象37
3.2.2 关闭内核对象38
3.3 跨进程边界共享内核对象42
3.3.1 使用对象句柄继承42
3.3.2 改变句柄的标志45
3.3.3 为对象命名46
3.3.4 终端服务命名空间50
3.3.5 专有命名空间51
3.3.6 复制对象句柄58
第II部分 工 作 机 理
第4章 进程65
4.1 编写第一个Windows应用程序66
4.1.1 进程实例句柄71
4.1.2 进程前一个实例的句柄72
4.1.3 进程的命令行73
4.1.4 进程的环境变量74
4.1.5 进程的关联性79
4.1.6 进程的错误模式79
4.1.7 进程当前所在的驱动器
和目录80
4.1.8 进程的当前目录81
4.1.9 系统版本82
4.2 CreateProcess函数85
4.2.1 pszApplicationName和
pszCommandLine参数86
4.2.2 psaProcess,psaThread
和bInheritHandles参数87
4.2.3 fdwCreate参数89
4.2.4 pvEnvironment参数91
4.2.5 pszCurDir参数92
4.2.6 psiStartInfo参数92
4.2.7 ppiProcInfo参数98
4.3 终止进程100
4.3.1 主线程的入口点函数返回100
4.3.2 ExitProcess函数101
4.3.3 TerminateProcess函数102
4.3.4 当进程中的所有线程终止时103
4.3.5 当进程终止运行时103
4.4 子进程104
4.5 管理员以标准用户权限运行时106
4.5.1 自动提升进程的权限109
4.5.2 手动提升进程的权限111
4.5.3 何为当前权限上下文112
4.5.4 枚举系统中正在运行的
进程114
4.5.5 Process Information示例
程序115
第5章 作业121
5.1 对作业中的进程施加限制124
5.2 将进程放入作业中131
5.3 终止作业中的所有线程132
5.4 作业通知135
5.5 Job Lab示例程序138
第6章 线程基础140
6.1 何时创建线程141
6.2 何时不应该创建线程143
6.3 编写第一个线程函数144
6.4 CreateThread函数144
6.4.1 psa参数145
6.4.2 cbStackSize参数145
6.4.3 pfnStartAddr和pvParam
参数146
6.4.4 dwCreateFlags147
6.4.5 pdwThreadID147
6.5 终止运行线程148
6.5.1 线程函数返回148
6.5.2 ExitThread函数148
6.5.3 TerminateThread函数149
6.5.4 进程终止运行时149
6.5.5 线程终止运行时150
6.6 线程内幕150
6.7 C/C++运行库注意事项153
6.7.1 用_beginthreadex而不要用
CreateThread创建线程161
6.7.2 绝对不应该调用的C/C++
运行库函数161
6.8 了解自己的身份162
第7章 线程调度、优先级和关联性165
7.1 线程的挂起和恢复166
7.2 进程的挂起和恢复167
7.3 睡眠169
7.4 切换到另一个线程169
7.5 在超线程CPU上切换到另一个
线程170
7.6 线程的执行时间170
7.7 在实际上下文中谈CONTEXT
结构174
7.8 线程优先级178
7.9 从抽象角度看优先级179
7.10 优先级编程182
7.10.1 动态提升线程优先级185
7.10.2 为前台进程微调调度程序186
7.10.3 调度I/O请求优先级186
7.10.4 Scheduling Lab 示例程序188
7.11 关联性192
第8章 用户模式下的线程同步197
8.1 原子访问:Interlocked系列函数198
8.2 高速缓存行203
8.3 高级线程同步205
8.4 关键段207
8.4.1 关键段:细节209
8.4.2 关键段和旋转锁212
8.4.3 关键段和错误处理213
8.5 Slim读/写锁214
8.6 条件变量217
8.6.1 Queue示例程序218
8.6.2 在停止线程时的死锁问题225
8.6.3 一些有用的窍门和技巧227
第9章 用内核对象进行线程同步230
9.1 等待函数232
9.2 等待成功所引起的副作用235
9.3 事件内核对象236
9.4 可等待的计时器内核对象245
9.4.1 让可等待的计时器添加APC
调用248
9.4.2 计时器的剩余问题250
9.5 信号量内核对象251
9.6 互斥量内核对象253
9.6.1 遗弃问题255
9.6.2 互斥量与关键段的比较256
9.6.3 Queue示例程序256
9.7 线程同步对象速查表264
9.8 其他的线程同步函数265
9.8.1 异步设备I/O265
9.8.2 WaitForInputIdle函数265
9.8.3 MsgWaitForMultipleObjects(Ex)
函数266
9.8.4 WaitForDebugEvent函数267
9.8.5 SignalObjectAndWait函数267
9.8.6 使用等待链遍历API来检测
死锁268
第10章 同步设备I/O与异步设备I/O275
10.1 打开和关闭设备276
10.2 使用文件设备285
10.2.1 取得文件的大小285
10.2.2 设置文件指针的位置286
10.2.3 设置文件尾288
10.3 执行同步设备I/O289
10.3.1 将数据刷新至设备289
10.3.2 同步I/O的取消290
10.4 异步设备I/O基础291
10.4.1 OVERLAPPED结构292
10.4.2 异步设备I/O的注意事项294
10.4.3 取消队列中的设备I/O
请求296
10.5 接收I/O请求完成通知296
10.5.1 触发设备内核对象297
10.5.2 触发事件内核对象298
10.5.3 可提醒I/O301
10.5.4 I/O完成端口306
10.5.5 模拟已完成的I/O请求316
第11章 Windows线程池324
11.1 情形1:以异步方式调用函数325
11.1.1 显式地控制工作项325
11.1.2 Batch示例程序327
11.2 情形2:每隔一段时间调用一个
函数330
11.3 情形3:在内核对象触发时调用
一个函数335
11.4 情形4:在异步I/O请求完成时
调用一个函数337
11.5 回调函数的终止操作339
11.5.1 对线程池进行定制340
11.5.2 得体地销毁线程池:
清理组342
第12章 纤程345
第III部分 内 存 管 理
第13章 Windows内存体系结构355
13.1 进程的虚拟地址空间355
13.2 虚拟地址空间的分区356
13.2.1 空指针赋值分区357
13.2.2 用户模式分区357
13.3 地址空间中的区域360
13.4 给区域调拨物理存储器361
13.5 物理存储器和页交换文件362
13.6 页面保护属性365
13.6.1 写时复制366
13.6.2 一些特殊的访问保护属性
标志367
13.7 实例分析367
13.8 数据对齐的重要性375
第14章 探索虚拟内存379
14.1 系统信息379
14.2 虚拟内存状态387
14.3 NUMA机器中的内存管理388
14.4 确定地址空间的状态391
14.4.1 VMQuery函数392
14.4.2 示例程序:虚拟内存映射397
第15章 在应用程序中使用虚拟内存400
15.1 预订地址空间区域400
15.2 给区域调拨物理存储器402
15.3 同时预订和调拨物理存储器403
15.4 何时调拨物理存储器405
15.5 撤销调拨物理存储器及释放区域407
15.5.1 何时撤销调拨物理存储器407
15.5.2 虚拟内存分配示例程序408
15.6 改变保护属性414
15.7 重置物理存储器的内容415
15.8 地址窗口扩展419
第16章 线程栈429
16.1 C/C++运行库的栈检查函数433
16.2 Summation示例程序435
第17章 内存映射文件440
17.1 映射到内存的可执行文件和DLL441
17.1.1 同一个可执行文件或DLL
的多个实例不会共享静态
数据442
17.1.2 在同一个可执行文件或DLL
的多个实例间共享静态
数据444
17.1.3 Application Instances示例
程序449
17.2 映射到内存的数据文件451
17.2.1 方法1:一个文件,一块
缓存451
17.2.2 方法2:两个文件,一块
缓存452
17.2.3 方法3:一个文件,两块
缓存452
17.2.4 方法4:一个文件,零个
缓存453
17.3 使用内存映射文件453
17.3.1 第1步:创建或打开文件
内核对象454
17.3.2 第2步:创建文件映射
内核对象455
17.3.3 第3步:将文件的数据映射
到进程的地址空间458
17.3.4 第4步:从进程的地址空间
撤销对文件数据的映射461
17.3.5 第5步和第6步:关闭文件
映射对象和文件对象462
17.3.6 File Reverse示例程序463
17.4 用内存映射文件来处理大文件469
17.5 内存映射文件和一致性470
17.6 给内存映射文件指定基地址471
17.7 内存映射文件的实现细节472
17.8 用内存映射文件在进程间共享
数据473
17.9 以页交换文件为后备存储器的
内存映射文件474
17.10 稀疏调拨的内存映射文件478
第18章 堆491
18.1 进程的默认堆491
18.2 为什么要创建额外的堆492
18.2.1 对组件进行保护493
18.2.2 更有效的内存管理493
18.2.3 使内存访问局部化494
18.2.4 避免线程同步的开销494
18.2.5 快速释放495
18.3 如何创建额外的堆495
18.3.1 从堆中分配内存块497
18.3.2 调整内存块的大小498
18.3.3 获得内存块的大小499
18.3.4 释放内存块500
18.3.5 销毁堆500
18.3.6 在C++中使用堆500
18.4 其他堆函数503
第IV部分 动态链接库
第19章 DLL基础509
19.1 DLL和进程的地址空间510
19.2 纵观全局512
19.2.1 构建DLL模块514
19.2.2 构建可执行模块519
19.2.3 运行可执行模块522
第20章 DLL高级技术524
20.1 DLL模块的显式载入和符号链接524
20.1.1 显式地载入DLL模块525
20.1.2 显式地卸载DLL模块529
20.1.3 显式地链接到导出符号532
20.2 DLL的入口点函数533
20.2.1 DLL_PROCESS_ATTACH
通知534
20.2.2 DLL_PROCESS_DETACH
通知535
20.2.3 DLL_THREAD_ATTACH
通知537
20.2.4 DLL_THREAD_DETACH
通知538
20.2.5 DllMain的序列化调用538
20.2.6 DllMain和C/C++运行库541
20.3 延迟载入DLL542
20.4 函数转发器553
20.5 已知的DLL553
20.6 DLL重定向555
20.7 模块的基地址重定位556
20.8 模块的绑定562
第21章 线程局部存储区565
21.1 动态TLS566
21.2 静态TLS570
第22章 DLL注入和API拦截572
22.1 DLL注入的一个例子573
22.2 使用注册表来注入DLL575
22.3 使用Windows挂钩来注入DLL576
22.4 使用远程线程来注入DLL587
22.4.1 Inject Library示例程序591
22.4.2 Image Walk DLL596
22.5 使用木马DLL来注入DLL598
22.6 把DLL作为调试器来注入598
22.7 使用CreateProcess来注入代码599
22.8 API拦截的一个例子599
22.8.1 通过覆盖代码来拦截API600
22.8.2 通过修改模块的导入段来
拦截API601
22.8.3 Last MessageBox Info示例
程序604
第V部分 结构化异常处理
第23章 终止处理程序621
第24章 异常处理程序与软件异常638
24.1 通过实例理解异常过滤程序
和异常处理程序638
24.1.1 Funcmeister1函数639
24.1.2 Funcmeister2函数639
24.2 EXCEPTION_EXECUTE_
HANDLER641
24.2.1 一些有用的例子642
24.2.2 全局展开645
24.2.3 停止全局展开647
24.3 EXCEPTION_CONTINUE_
EXECUTION648
24.4 EXCEPTION_CONTINUE_
SEARCH650
24.5 GetExceptionCode652
24.6 GetExceptionInformation656
24.7 软件异常659
第25章 未处理异常、向量化异常处理
与C++异常663
25.1 UnhandledExceptionFilter函数
详解665
25.2 即时调试671
25.3 电子表格示例程序673
25.4 向量化异常和继续处理程序681
25.5 C++异常与结构化异常的比较683
25.6 异常与调试器684
第26章 错误报告与应用程序恢复688
26.1 Windows错误报告控制台688
26.2 可编程的Windows错误报告691
26.3 对进程中所有的问题报告进行
定制693
26.4 问题报告的创建与定制694
26.4.1 创建一个自定义的问题
报告697
26.4.2 设置报告参数:
WerReportSetParameter698
26.4.3 将小型转储文件放入报告:
WerReportAddDump698
26.4.4 将任意文件放入报告:
WerReportAddFile699
26.4.5 修改对话框文本:
WerReportSetUIOption700
26.4.6 提交错误报告:
WerReportSubmit700
26.4.7 关闭问题报告:
WerReportCloseHandle702
26.4.8 Customized WER示例
程序702
26.5 应用程序的自动重启与恢复708
26.5.1 应用程序的自动重启708
26.5.2 对应用程序恢复的支持709
第VI部分
附录A 构建环境713
附录B 消息处理宏、子控件宏和API宏724
索引729