深入浅出MFC一
Contents
[Trial version] 目录
[Trial version] 第0章你一定要知道(导读)
[Trial version] 第1章Win32基本程序观念
[Trial version] 第2章C++的重要性质
[Trial version] 第3章MFC六大关键技术之模拟
[Trial version] 第5章总观AlicationFramework
[Trial version] 第6章MFC程序设计导论
[Trial version] 第7章简单而完整:MFC骨干程序
[Trial version] 第8章Document-View深入探讨
[Trial version] 第9章 消息映射与命令绕行
[Trial version] 第10章MFC与对话框
[Trial version] 第11章View功能之加强与重绘效率之提升
[Trial version] 第12章打印与预览
[Trial version] 第13章多重文件与多重显示
[Trial version] 第14章MFC多线程程序设计
[Trial version] 第15章定制一个AWizard
[Trial version] 第16章站上众人的肩膀--使用Comonents&am;amActiveXControls
[Trial version] 附录A无责任书评
[Amber demo]
owered By Gisun htt://.gisun.com
目 录
第0章 你一定要知道(导读)/1
这本书适合谁/1
你需要什么技术基础/1
你需要什么软硬件环境
让我们使用同一种语言
本书符号习惯/3
磁盘内容与安装
范例程序说明
第一篇 勿在浮砂筑高台 - 本书技术前提/3
第1章 Win32 程序基本观念/3
Win32程序开发流程/4
需要什么函数库(.LIB)/4
需要什么头文件(.H)/4
以消息为基础以事件驱动之/5
一个具体而微的Win32 程序/5
程序进入点WinMain/10
窗口类之注册与窗口之诞生/11
消息循环/12
窗口的生命中枢—窗口函数/12
消息映射(Message Ma)雏形/13
对话框的运作/14
模块定义文件(.DEF)/14
资源描述文件(.RC) /15
Windows 程序的生与死/15
闲置时间的处理:OnIdle /16
Console 程序/17
Console 程序与 DOS 程序的差别/17
Console 程序的编译链接/18
JBACKU:Win32 Console 程序设计/19
MFCCON:MFC Console 程序设计/20
什么是C Runtime Library 的多线程版本/22
进程与线程(rocess and Thread)/22
核心对象/22
一个进程的诞生与死亡/23
产生子进程/23
一个线程的诞生与死亡/24
以_beginthreadex取代CreateThread/25
线程优先权(riority)/26
多线程程序设计实例/27
第2章 C++ 的重要性质 /29
类及其成员—谈封装(encasulation)/29
基类与派生类—谈继承(Inheritance)/29
this 指针 /31
虚函数与多态(olymorhism)/32
类与对象大解剖 /40
Object slicing 与虚函数 /42
静态成员(变量与函数) /44
C++程序的生与死:兼谈构造函数与析构函数 /46
四种不同的对象生存方式 /47
所谓“Unwinding”/48
运行时类型信息(RTTI) /48
动态生成(Dynamic Creation) /50
异常处理(Excetion Handling) /50
Temlate /53
Temlate Functions /53
Temlate Classes /54
Temlates 的编译与链接 /56
第3章 MFC六大关键技术之模拟/57
MFC类阶层/57
Frame1范例程序/57
MFC程序的初始化过程/59
Frame2范例程序/61
RTTI(运行时类型辨识)/65
CRuntimeClass与类型录 /65
DECLARE_DYNAMIC / IMLEMENT_DYNAMIC宏/66
Frame3 范例程序/71
IsKindOf(类型辨识)/77
Frame4 范例程序/77
Dynamic Creation(动态生成)/78
DECLARE_DYNCREATE / IMLEMENT_DYNCREATE 宏 /79
Frame6 范例程序 /84
ersistence(永续生存)机制 /91
Serialize(数据读写) /91
DECLARE_SERIAL/IMLEMENT_SERIAL 宏 /95
没有范例程序
Message Maing(消息映射)/97
Frame7 范例程序/104
Command Routing(命令循环)/112
Frame8 范例程序/119
本章回顾/130
第二篇 欲善工事先利其器- Visual C++ 5.0 开发工具
第4章 Visual C++ - 整合性软件开发环境
安装与组成
四个重要的工具
内务府总管:Visual C++ 整合开发环境
关于roject
关于工具设定
Source Browser
Online Hel
除错工具
VC++ 除错器
Excetion Handling
程序代码产生器—AWizard
东圈西点完成 MFC 程序骨干
Scribble Ste0
威力强大的资源器
Icon 器
Cursor器
Bitma器
ToolBar器
VERSIONINFO资源器
String Table器
Menu 器
Accelerator 器
Dialog 器
Console 程序的项目管理
第三篇 浅出MFC程序设计
第5章 总观Alication Framework /130
什么是Alication Framework /130
侯捷怎么说 /130
我怎么说 /131
别人怎么说 /133
为什么使用 Alication Framework /134
Microsoft Foundation Class(MFC) /136
白头宫女话天宝:Visual C++与MFC/137
纵览MFC /138
General urose classes /138
Windows AI classes /139
Alication framework classes /140
High level abstractions /140
Afx全局函数 /140
MFC宏(macros) /141
MFC数据类型(data tye)/142
第6章 MFC程序设计导论——MFC程序的生死因果 /144
不二法门:熟记MFC类的阶层架构 /144
需要什么函数库(.LIB) /146
需要什么含入文件(.H) /146
简化的MFC程序架构—以Hello MFC为例 /148
Hello 程序原始代码 /148
MFC 程序的来龙去脉 /152
我只借用两个类:CWinA和CFrameWnd /152
CWinA—取代WinMain的地位 /152
CFrameWnd—取代Wndroc的地位 /154
引爆器—Alication object /155
隐晦不明的 WinMain /156
AfxWinInit - AFX 内部初始化动作 /158
CWinA::InitAlication /160
CMyWinA::InitInstance /160
CFrameWnd::Create 产生主窗口(并注册窗口类)/161
奇怪的窗
口类名称 Afx:b:14ae:6:3e8f/168
窗口显示与更新 /170
CWinA::Run - 程序生命的活水源头/170
把消息与处理函数串接在一起:Message Ma机制/172
来龙去脉总整理/173
Callback 函数/174
闲置时间(idle time)的处理:OnIdle/176
Dialog 与 Control/178
通用对话框(Common Controls)/178
本章回顾/179
第7章 简单而完整:MFC 骨干程序/180
不二法门:熟记 MFC 类的阶层架构/180
MFC程序的UI新风貌/180
Document/View 支撑你的应用程序 /181
利用Visual C++工具完成Scribble ste0 /183
骨干程序使用哪些MFC类?/183
Document Temlate的意义 /187
Scribble的Document/View 设计/190
主窗口的诞生/192
工具列和状态列的诞生(Toolbar &am; Status bar)/193
鼠标拖放(Drag and Dro)/195
消息映射(Message Ma)/196
标准菜单File/Edit/View/Window/Hel/196
对话框 /199
改用CEditView /199
第四篇 深入MFC程序设计 /199
第8章 Document-View 深入探讨 /200
为什么需要 Document-View(形而上)/200
Document /200
View /201
Document Frame(View Frame)/202
Document Temlate /202
CDocTemlate 管理 CDocument / CView / CFrameWnd /202
Scribble Ste1 的 Document(数据结构设计) /207
MFC Collection Classes 的选用 /207
Temlate-Based Classes /208
Temlate-Based Classes 的使用方法 /209
CScribbleDoc 的修改 /209
SCRIBBLEDOC.H /211
SCRIBBLEDOC.C /212
文件:一连串的线条 /215
CScribbleDoc 的成员变量 /215
CObList /215
CScribbleDoc 的成员函数 /215
线条与坐标点 /217
CStroke 的成员变量 /217
CArray<Coint, Coint> /217
CStroke 的成员函数 /217
Scribble Ste1 的 View:数据重绘与 /218
CScribbleView 的修改 /218
SCRIBBLEVIEW.H /219
SCRIBBLEVIEW.C /220
View 的重绘动作—GetDocument和OnDraw /222
CScribbleView的成员变量 /222
CScribbleView的成员函数 /223
View 与使用者的交谈(鼠标消息处理实例)/223
ClassWizard 的辅佐 /224
WizardBar 的辅佐 /225
Serialize:对象的文件读写 /225
Serialization以外的文件读写动作 /226
台面上的Serialize动作 /227
台面下的Serialize写文件奥秘 /231
台面下的Serialize读文件奥秘 /233
DYNAMIC / DYNCREATE / SERIAL 三宏/240
Serializable 的必要条件/244
CObject 类/245
IsKindOf/245
IsSerializable/245
CObject::Serialize/245
CArchive类/246
oerator<<和oerator>>/246
效率考虑/250
自定 SERIAL宏给抽象类使用 /250
在CObList中加入 CStroke 以外的类 /250
Document与View 交流—为Scribble Ste4做准备/254
第9章 消息映射与命令循环 /255
到底要解决什么 /255
消息分类 /256
万流归宗 Command Target(CCmdTarget)/256
三
个奇怪的宏一张巨大的 /257
DECLARE_MESSAGE_MA 宏/257
消息映射的形成:BEGIN_/ON_/END_ 宏 /258
米诺托斯(Minotauros)与西修斯(Theseus)/261
两万五千里长征—消息的流窜 /265
直线上溯(一般 Windows 消息) /265
拐弯上溯(WM_COMMAND 命令消息) /268
罗塞达碑石:AfxSig_xx 的秘密/273
Scribble Ste2:UI 对象的变化/277
改变菜单/277
改变工具列/278
利用ClassWizard连接命令项识别代码与命令处理函数/280
维护UI对象状态(UDATE_COMMAND_UI)/282
本章回顾/285
第10章 MFC 与对话框/285
对话框器/286
利用ClassWizard 连接对话框与其专属类/288
ENDLG.H /290
ENDLG.C /291
对话框的消息处理函数 /292
MFC中各式各样的MA /294
对话框数据交换与查核(DDX &am; DDV)/294
MFC中各式各样的DDx_函数 /297
如何唤起对话框 /297
本章回顾 /299
第11章 View功能之加强与重绘效率之提升/299
同时修改多个 Views:UdateAllViews 和 OnUdate/300
在View中定义一个 hint/302
把hint传给 OnUdate/304
利用hint增加重绘效率/305
可卷动的窗口:CScrollView /307
大窗口中的小窗口:Slitter /313
分裂窗口的功能 /313
分裂窗口的程序概念/314
分裂窗口之实现/315
本章回顾 /317
第12章 印
与预览/317
概观/317
打印动作的后台原理 /320
MFC预设的打印机制 /324
Scribble打印机制的补强 /333
打印机的页和文件的页 /333
配置GDI绘图工具 /334
尺寸与方向:关于映射模式(坐标系统)/334
分页/336
表头(Header)与表尾/338
动态计算页代码/338
打印预览(rint review)/339
本章回顾/339
第13章 多重文件与多重显示 /339
MDI 和 SDI /340
多重显像(Multile Views) /340
窗口的动态分裂 /342
窗口的静态分裂 /343
CreateStatic 和 CreateView /343
窗口的静态三叉分裂 /345
Grah 范例程序 /346
静态分裂窗口之观念整理 /354
同源子窗口 /355
CMDIFrameWnd::OnWindowNew/355
Text 范例程序 /356
非制式作法的缺点 /361
多重文件 /361
新的Document类 /362
新的Document Temlate /363
新的UI系统 /364
新文件的文件读写动作 /365
第14章 MFC多线程程序设计(Multi-threaded rogramming in MFC)/367
从操作系统层面看线程/367
三个观念:模块、进程、线程/367
线程优先权(riority) /368
线程排程(Scheduling) /369
Thread Context /370
从程序设计层面看线程 /371
Worker Threads 和UI Threads /371
错误观念 /372
正确态度 /372
MFC多线程程序设计 /372
探索CwinThread/372
产生一个Worker Thread/374
产生一个UI Thread /375
线程的结束/376
线程
与同步控制 /376
MFC多线程程序实例 /378
第15章 定制一个AWizard /380
到底Wizard是什么? /381
Custom AWizard 的基本操作 /381
剖析AWizard Comonents /385
Dialog Temlates 和Dialog Classes /385
Macros /386
Directives /387
动手修改To Studio AWizard/387
利用资源器修改IDD_CUSTOM1对话窗画面/387
利用ClassWizard 修改CCustom1Dlg类 /388
改写OnDismiss 虚函数在其中定义macros /389
修改text temlate/389
To Studio AWizard执行结果/390
更多的信息/390
第16章 站上众人的肩膀—使用Comonents和ActiveX Controls/391
什么是Comonent Gallery /391
使用 Comonents /393
Slash screen /393
System Info for About Dlg /394
Tis of the Day /394
Comonents实际运用:ComTest 程序/395
修改ComTest 程序内容 /409
使用ActiveX Controls /411
ActiveX Control 基础观念:roerties、Methods、Events/411
ActiveX Controls 的五大使用步骤/412
使用“Grid”ActiveX Control:OcxTest 程序/413
[Amber demo]
owered By Gisun htt://.gisun.com
第0章 你一定要知道(导读)
这本书适合谁
深入浅出MFC是一本介绍MFC(Microsoft Foundation Classes)程序设计技术的书籍。对于Windows 应用软件的开发感到兴趣并欲使用Visual C++ 整合环境的视觉开发工具以MFC为程序基础的人都可以从此书获得最根本最重要的知识与实例。
如果你是一位对Alication Framework和面向对象(Object Oriented)观念感兴趣的技术狂热份子想知道神秘的Runtime Tye Information、Dynamic Creation、ersistence、Message Maing 以及Command Routing 如何实现本书能够充分满足你。事实上依我之见这些核心技术与彻底学会操控MFC乃同一件事情。
全书分为四篇:
第一篇勿在浮砂筑高台提进入 MFC 核心技术以及应用技术之前的所有技术基础包括:
Win32 程序观念 :message based,event driven,multitasking, multithreading, console rogramming。
C++ 重要技术:类与对象、this 指针与继承、静态成员、虚函数与多态、模板(temlate)类、异常处理(excetion handling)。
MFC 六大技术之简化仿真(Console 程序)
第二篇欲善工事先利其器提给对Visual C++ 整合环境全然陌生的朋友一个导引。这一篇当然不能取代 Visual C++ User's Guide 的地位但对整个软件开发环境有全盘以及概观性的介绍可以让初学者迅速了解手上掌握的工具以及它们的主要功能。
第三篇浅出 MFC 程序设计介绍一个 MFC 程序的生死因果。已经有 MFC 程序经验的朋友不见得不会对本篇感到惊艳。根据我的了解太多人使用 MFC 是「只知道这么做不知道为什么」;本篇详细
解释 MFC 程序之来龙去脉为初入 MFC 领域的读者奠定扎实的基础。说不定本篇会让你有醍醐灌顶之感。
第四篇深入 MFC 程序设计介绍各式各样 MFC 技术。「只知其然 不知其所以然」的不良副作用在程序设计的企图进一步开展之后愈来愈严重最终会行不得也!那些最困扰我们的 MFC 宏、MFC 常数定义不得一窥堂奥的 MFC 黑箱作业在本篇陆续曝光。本篇将使您高喊:Eureka!
阿基米得在洗澡时发现浮力原理高兴得来不及穿上裤子跑到街上大喊:Eureka(我找到了)。
范例程序方面第三章有数个Console程序(DOS-like 程序在Windows系统的DOS Box 中执行)模拟并简化Alication Framework 六大核心技术。另外全书以一个循序渐进的Scribble 程序(Visual C++ 所附范例)从第七章开始分章探讨每一个MFC应用技术主题。第13章另有三个程序示范 Multi-View 和 Multi-Document 的情况。
14章~16 章是第二版新增内容主题分别是MFC 多线程程序设计、Custom AWizard、以及如何使用Comonent Gallery 提的ActiveX controls 和comonents。
你需要什么技术基础
从什么技术层面切入Windows软件开发领域?C/SDK?抑或C++/MFC?这一直是个引起争议的论题。就我个人观点C++/MFC 程序设计必须跨越四大技术障碍:
1. 面向对象观念与C++ 语言。
2. Windows 程序基本观念(程序进入点、消息流动、窗口函数、callback...)。
3. Microsoft Foundation Classes(MFC)本身。
4. Visual C++ 整合环境与各种开发工具(难度不高但需熟练)。
换言之如果你从未接触C++千万不要阅读本书那只会打击你学习新技术的信心而已。如果已接触过C++ 但不十分熟悉你可以一边复习C++ 一边学习MFC这也是我所鼓励的方式(很多人是为了使用MFC 而去学习C++ 的)。C++ 语言的继承(inheritance)特性对于我们使用MFC尤为重要因为使用MFC 就是要继承各个类并为己用。所以你应该对C++ 的继承特质(以及虚函数当然)多加体会。我在第2章安排了一些C++ 的必要基础。我所挑选的题目都是本书会用到的技术而其深度你不见得能够在一般 C++ 书籍中发现。
如果你有C++ 语言基础但从未接触过Win16 或 Win32 程序设计只在 DOS 环境下开发过软件我在第1章为你安排了一些 Win32 程序设计基础。这个基础至为重要只会在各个 Wizards上按来按去却不懂所谓 message loo 与 window rocedure 的人不可能搞定 Windows 程序设计——不管你用的是MFC或OWL或Oen Class Library不管你用的是Visual C++或Borland C++或VisualAge C++。
名词界定:
AI—Alication rogramming Interface 系统开放出来给
程序员使用的接口就是AI。一般人的观念中AI是指像 C 函数那样的东西不尽然!DOS 的中断向量(interrut vector)也可以说是一种AIOLE Interface(以 C++ 类的形式呈现)也可以说是一种 AI。不是有人这么说吗:MFC 势将成为 Windows 环境上标准的 C++ AI(我个人认为这句话已成为事实)。
SDK—Software Develoment Kit 原指软件开发工具。每一套环境都可能有自己的SDK例如har La的386|DOS Extender 也有自己的SDK。在Windows这一领域SDK原是指Microsoft 的软件开发工具但现在已经变成一个一般性名词。凡以Windows raw AI 撰写的程序我们通常也称为SDK程序。也有人把Windows AI称为SDK AI。Borland 公司的C++ 编译器也支持相同的SDK AI(那当然因为Windows只有一套)。本书如果出现「SDK 程序」这样的名词指的就是以 Windows raw AI 完成的程序。
MFC—Microsoft Foundation Classes 的缩写这是一个架构在Windows AI之上的C++ 类库(C++ Class Library)意图使 Windows 程序设计过程更有效率更符合面向对象的精神。MFC 在争取成为「Windows 类库标准」的上声势浩大。Symantec C++以及WATCOM C/C++已向微软取得授权在它的软件开发平台上 MFC。Borland C++也可以吃进MFC程序代码——啊OWL 的地位益形尴尬了。
OWL—Object Windows Library 的缩写这也是一个具备Alication Framework 架势的 C++ 类库附含在 Borland C++ 之中。
Alication Framework—在面向对象领域中这是一个专有名词。关于它的意义本书第5章有不少介绍。基本上它可以说是一个更有凝聚力关联性更强的类库。并不是每一套C++类库都有资格称为Alication Framework不过MFC和OWL都可入列IBM 的 Oen Class Library 也是。Alication Framework 当然不一定得是C++类库Java和 Delhi 应该也都称得上。
为使全书文字流畅精简我用了一些缩写字:
AI - Alication rogramming Interface
DLL - Dynamic Link Library
GUI - Grahics User Interface
MDI - Multile Document Interface
MFC - Microsoft Foundation Class
OLE - Object Linking &am; Embedded
OWL - Object Windows Library
SDK - Software Develoment Kit
SDI - Single Document Interface
UI - User Interface
WinA : Windows Alication
以下是本书使用之中英文名词对照表:
Control 控制组件如 Edit、ListBox、Button...。
drag &am; dro 拖放(鼠标左键按下选中图示后拖动然后放开)
Icon 图标(窗口缩小化后的小图样)
linked-list 串列
listbox 列表框、列表清单
notification 通告消息(发生于控制组件)
reemtive 强制性、先占式、优先权式
rocess 进程(一个执行起
来的程序)
queue 队列
temlate C++ 有所谓的class temlate一般译为类模板;Windows 有所谓的dialog temlate我把它译为对话框模板;MFC 有所谓的Document Temlate我没有译它(其义请见第7章和第8章)
window class 窗口类(不是一种C++ 类)
window focus 窗口焦点(拥有焦点之窗口将可以获得键盘输入)
class 类
object 对象
constructor 构造函数
destructor 析构函数
oerator 运算符
override 改写
overloading 重载 亦有他书译为「过荷」
Encasulation 封装
Inheritance 继承
Dynamic Binding 动态联编 亦即后期联编(late binding)
virtual function 虚函数
olymorhism 多态 亦有他书译为「同名异式」
member function 成员函数
data member 成员变量亦有他书译为「数据成员」
Base Class 基类亦即父类
Derived Class 派生类亦即子类
本书符号习惯
斜体字表示函数、常数、变量、语言保留字、宏、识别代码等等例如:
CreateWindow 这是Win32 函数
Strtok 这是C Runtime函数库的函数
WM_CREATE 这是Windows消息
ID_FILE_OEN 这是资源识别代码(ID)
CDocument::Serialize 这是MFC类的成员函数
m_NewViewClass 这是MFC类的成员变量
BEGIN_MESSAGE_MA 这是MFC宏
ublic 这是C++语言保留字
第一篇 勿在浮砂築高台
[Amber demo]
owered By Gisun htt://.gisun.com
第1章 Win32 基本程序观念
程序设计领域里每一个人都想飞。
但是还没学会走之前连跑都别想!
虽然这是一本深入讲解MFC 程序设计的书我仍坚持要安排这第一章介绍 Win32 的 基本程序设计原理(也就是所谓的SDK 程序设计原理)。从来不曾学习过在「事件驱动(event driven)系统」中撰写「以消息为基础(message based)之应用程序」者能否一步跨入MFC 领域直接以alication framework 开发 Windows 程序我一直抱持怀疑的态度。虽然有了MFC(或任何其它的alication framework)你可以继承一整组类从而快速得到一个颇具规模的程序但是 Windows 程序的运作 本质(Message BasedEvent Driven)从来不曾也不会改变。如果你不能了解其髓空有 其皮其肉或其骨是不可能有所精进的即使能够操控 wizard充其量却也只是个 uet对于手上的程序代码没有自主权。
我认为学习MFC之前必要的基础是对于Windows程序的事件驱动特性的了解(包括消息的产生、获得、分派、判断、处理)以及对 C++ 多态(olymor
hism)的精确体会。本章所提出的是我对第一项必要基础的探讨你可以从中获得关于 Windows 程序的诞生与死亡以及多任务环境下程序之间共存的观念。至于第二项基础将由第二章为你夯实。
==================================
ABC Amber CHM Converter 7.31
Trial version
==================================
图1-1 一个32位Windows SDK程序的开发流程
需要什么函数库(.LIB)
众所周知Windows 支持动态链接。换句话说应用程序所调用的Windows AI 函数是在「运行时」才链接上的。那么「链接时期」所需的函数库做什么用?有哪些?
并不是延伸文件名为 .dll 者才是动态链接函数库(DLLDynamic Link Library)事实上 .exe、.dll、.fon、.mod、.drv、.ocx 都是所谓的动态链接函数库。
Windows 程序调用的函数可分为 C Runtimes 以及 Windows AI 两大部分。早期的 C Runtimes 并不支持动态链接但Visual C++ 4.0 之后已支持并且在32 位操作系统中已不再有small/medium/large 等内存模式之分。以下是它们的命名规则与使用时机 :
LIBC.LIB - 这是C Runtime 函数库的静态链接版本。
MSVCRT.LIB - 这是C Runtime 函数库动态链接版本(MSVCRT40.DLL)的 imort 函数库。如果链接此一函数库你的程序执行时必须有 MSVCRT40.DLL 在场。
另一组函数Windows AI由操作系统本身(主要是 Windows 三大模块 GDI32.DLL 和 USER32.DLL 和 KERNEL32.DLL)提(注)。虽说动态链接是在运行时才发生「链接」事实但在链接时期链接器仍需先为调用者(应用程序本身)准备一些适当的资讯才能够在运行时顺利「跳」到 DLL 执行。如果该 AI 所属之函数库尚未加载系统也才因此知道要先行加载该函数库。这些适当的信息放在所谓的「imort 函数库」中。32 位 Windows 的三大模块所对应的 imort 函数库分别为 GDI32.LIB 和 USER32.LIB 和 KERNEL32.LIB。
Windows 发展至今逐渐加上的一些新的 AI 函数(例如 Common Dialog、ToolHel) 并不放在GDI和USER 和KERNEL三大模块中而是放在诸如COMMDLG.DLL、 TOOLHEL.DLL之中。如果要使用这些AIs链接时还得加上这些DLLs 所对应的imort函数库诸如COMDLG32.LIB 和 TH32.LIB。
很快地在稍后的范例程序“Generic” 的makefile中你就可以清楚看到链接时期所需的各式各样函数库(以及各种链接器选项)。
需要什么头文件(.H)
所有Windows程序都必须含入WINDOWS.H。早期这是一个巨大的头文件大约有5000 行左右Visual C++ 4.0 已把它切割为各个较小的文件但还以 WINDOWS.H 总括之。 除非你十分清楚什么 AI 动作需要什么头文件否则为求便利单单一个 WINDOWS.H 也就是了。
不过WINDOWS.H
只照顾三大模块所提的AI 函数如果你用到其它 system DLLs例如 COMMDLG.DLL 或 MAI.DLL 或 TAI.DLL 等等就得含入对应的头文件例如COMMDLG.H 或 MAI.H 或 TAI.H 等等。
以消息为基础以事件驱动之(message basedevent driven)
Windows 程序的进行系依靠外部发生的事件来驱动。换句话说程序不断等待(利用一个 while 循环)等待任何可能的输入然后做判断然后再做适当的处理。上述的「输入」是由操作系统捕捉到之后以消息形式(一种数据结构)进入程序之中。操作系统如何捕捉外围设备(如键盘和鼠标)所发生的事件呢?噢USER 模块掌管各个外围的驱动程序它们各有侦测循环。
如果把应用程序获得的各种「输入」分类可以分为由硬件装置所产生的消息(如鼠标移动或键盘被按下)放在系统队列(system queue)中以及由 Windows 系统或其它Windows 程序传送过来的消息放在程序队列(alication queue)中。以应用程序的眼光来看消息就是消息来自哪里或放在哪里其实并没有太大区别反正程序调用GetMessage AI就取得一个消息程序的生命靠它来推动。所有的GUI系统包括UNIX的X Window 以及OS/2的resentation Manager都像这样是以消息为基础的事件驱动系统。
可想而知每一个Windows程序都应该有一个循环如下:
MSG msg;
while (GetMessage(&am;msg, NULL, NULL, NULL)) {
TranslateMessage(&am;msg);
DisatchMessage(&am;msg);
} // 以上出现的函数都是Windows AI 函数
消息也就是上面出现的MSG结构其实是Windows内定的一种数据格式:
/* Queued message structure */
tyedef struct tagMSG
{
HWND hwnd;
UINT message; // WM_xxx例如 WM_MOUSEMOVEWM_SIZE...
WARAM waram;
LARAM laram;
DWORD time;
OINT t;
} MSG;
接受并处理消息的主角就是窗口。每一个窗口都应该有一个函数负责处理消息程序员必须负责设计这个所谓的「窗口函数」(window rocedure或称为window function)。如果窗口获得一个消息这个窗口函数必须判断消息的类决定处理的方式。
以上就是Windows程序设计最重要的观念。至于窗口的产生与显示十分简单有专门的AI函数负责。稍后我们就会看到 Windows 程序如何把这消息的取得、分派、处理动作表现出来。
一个具体而微的Win32程序
许多相关书籍或文章尝试以各种方式简化Windows程序的第一步因为单单一个Hello程序就要上百行怕把大家吓坏了。我却宁愿各位早一点接触正统写法早一点看到全 貌。Windows 的东西又多又杂早一点一窥全貌是很有必要的。而且你会发现经过有 条理的解释之后程序
代码的多寡其实构不成什么威胁(否则无字天书最适合程序员阅 读)。再说上百进程序代码哪算得了什么!
你可以从图1-2 得窥 Win32 应用程序的本体与操作系统之间的关系。Win32 程序中最具代表意义的动作已经在该图显示出来完整的程序代码展示于后。本章后续讨论都围绕着此一程序。
稍后会出现一个makefile。关于makefile的语法可能已经不再为大家所熟悉了。我想我有必要做个说明。所谓makefile就是让你能够设定某个文件和某个文件相比——比较其产生日期。由其比较结果来决定要不要做某些你所指定的动作。例如:
generic.res : generic.rc generic.h
rc generic.rc
意思就是拿冒号(:)左边的generic.res和冒号右边的generic.rc 和generic.h 的文件日期相比。只要右边任一文件比左边的文件更新就执行下一行所指定的动作。这动作可以是任何命令列动作本例为rc generic.rc。
因此我们就可以把不同文件间的依存关系做一个整理以makefile 语法描述以产生必要的编译、链接动作。makefile 必须以NMAKE.EXE(Microsoft 工具)或MAKE.EXE(Borland 工具)处理之或其它编译器套件所附的同等工具(可能也叫做MAKE.EXE)处理之。
==================================
ABC Amber CHM Converter 7.31
Trial version
==================================
图 1-2 Windows 程序的本体与操作系统之间的关系
Generic.mak(请在DOS窗口中执行nmake generic.mak。环境设定请参考 .224)
#0001 # filename : generic.mak
#0002 # make file for generic.exe (Generic Windows Alication)
#0003 # usage : nmake generic.mak (Microsoft C/C++ 9.00) (Visual C++ 2.x)
#0004 # usage : nmake generic.mak (Microsoft C/C++ 10.00) (Visual C++ 4.0)
#0005
#0006 all: generic.exe
#0007
#0008 generic.res : generic.rc generic.h
#0009 rc generic.rc
#0010
#0011 generic.obj : generic.c generic.h
#0012 cl-c-W3-Gz-D_X86_-DWIN32 generic.c
#0013
#0014 generic.exe : generic.obj generic.res
#0015 link/MACHINE:I386 -subsystem:windows generic.res generic.obj \
#0016 libc.lib kernel32.lib user32.lib gdi32.lib
Generic.h
#0001 //---------------------------------------------------------------
#0002 // 文件名 : generic.h
#0003 //---------------------------------------------------------------
#0004 BOOL InitAlication(HANDLE);
#0005 BOOL InitInstance(HANDLE, int);
#0006 LRESULT CALLBACK Wndroc(HWND, UINT, WARAM, LARAM);
#0007 LRESULT CALLBACK About(HWND, UINT, WARAM, LARAM);
Generic.c(粗体代表Windows AI函数或宏)
#0001 //---------------------------------------------------------------
#0002 // Generic - Win32 程序的基础写法
#0003 // To Studio * J
.J.Hou
#0004 // 文件名 : generic.c
#0005 // 作者 : 侯俊杰
#0006 // 编译链接 : 请参考 generic.mak
#0007 //---------------------------------------------------------------
#0008
#0009 #include <windows.h> // 每一个 Windows 程序都需要含入此文件
#0010 #include "resource.h" // 内含各个 resource IDs
#0011 #include "generic.h" // 本程序之含入文件
#0012
#0013 HINSTANCE _hInst; // Instance handle
#0014 HWND _hWnd;
#0015
#0016 char _szAName[] = "Generic"; // 程序名称
#0017 char _szTitle[]= "Generic Samle Alication"; // 窗口标题
#0017 char _szTitle[]
#0018
#0019 //---------------------------------------------------------------
#0020 // WinMain - 程序进入点
#0021 //---------------------------------------------------------------
#0022 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hrevInstance,
#0023 LSTR lCmdLine, int nCmdShow)
#0024 {
#0025 MSG msg;
#0026
#0027 UNREFERENCED_ARAMETER(lCmdLine); // 避免编译时的警告
#0028
#0029 if (!hrevInstance)
#0030 if (!InitAlication(hInstance))
#0031 return (FALSE);
#0032
#0033 if (!InitInstance(hInstance, nCmdShow))
#0034 return (FALSE);
#0035
#0036 while (GetMessage(&am;msg, NULL, 0, 0)) {
#0037 TranslateMessage(&am;msg);
#0038 DisatchMessage(&am;msg);
#0039 }
#0040
#0041 return (msg.waram); // 传回 ostQuitMessage 的参数
#0042 }
#0043 //---------------------------------------------------------------
#0044 // InitAlication - 注册窗口类
#0045 //---------------------------------------------------------------
#0046 BOOL InitAlication(HINSTANCE hInstance)
#0047 {
#0048 WNDCLASS wc;
#0049
#0050 wc.style = CS_HREDRAW | CS_VREDRAW;
#0051 wc.lfnWndroc= (WNDROC)Wndroc; // 窗口函数
#0052 wc.cbClsExtra= 0;
#0053 wc.cbWndExtra= 0;
#0054 wc.hInstance= hInstance;
#0055 wc.hIcon= LoadIcon(hInstance, "jjhouricon");
#0056 wc.hCursor= LoadCursor(NULL, IDC_ARROW);
#0057 wc.hbrBackground = GetStockObject(WHITE_BRUSH); // 窗口后台颜色
#0058 wc.lszMenuName = "GenericMenu"; // .RC 所定义的窗体
#0059 wc.lszClassName = _szAName;
#0060
#0061 return (RegisterClass(&am;wc));
#0062 }
#0063 //---------------------------------------------------------------
#0064 // InitInstance - 产生窗口
#0065 //---------------------------------------------------------------
#0066 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
#0067 {
#0068 _hInst = hInstance; // 储存为全局变量方便使用。
#0069
#0070 _hWnd = CreateWindow(
#0071 _szAName,
#0072 _s
zTitle,
#0073 WS_OVERLAEDWINDOW,
#0074 CW_USEDEFAULT,
#0075 CW_USEDEFAULT,
#0076 CW_USEDEFAULT,
#0077 CW_USEDEFAULT,
#0078 NULL,
#0079 NULL,
#0080 hInstance,
#0081 NULL
#0082 );
#0083
#0084 if (!_hWnd)
#0085 return (FALSE)
#0086
#0087 ShowWindow(_hWnd, nCmdShow); // 显示窗口
#0088 UdateWindow(_hWnd); // 送出 WM_AINT
#0089 return (TRUE);
#0090 }
#0091 //---------------------------------------------------------------
#0092 // Wndroc - 窗口函数
#0093 //---------------------------------------------------------------
#0094 LRESULT CALLBACK Wndroc(HWND hWnd, UINT message,
#0095 WARAM waram, LARAM laram)
#0096 {
#0097 int wmId, wmEvent;
#0098
#0099 switch (message) {
#0100 case WM_COMMAND:
#0101
#0102 wmId = LOWORD(waram);
#0103 wmEvent = HIWORD(waram);
#0104
#0105 switch (wmId) {
#0106 case IDM_ABOUT:
#0107 DialogBox(_hInst,
#0108 "AboutBox",// 对话框资源名称
#0109 hWnd, // 父窗口
#0110 (DLGROC)About // 对话框函数名称
#0111 );
#0112 break;
#0113
#0114 case IDM_EXIT: // 使用者想结束程序。处理方式与 WM_CLOSE 相同。
#0116 DestroyWindow(hWnd);
#0117 break;
#0118
#0119 default:
#0120 return (DefWindowroc(hWnd, message, waram, laram));
#0121 }
#0122 break;
#0123
#0124 case WM_DESTROY: // 窗口已经被摧毁 (程序即将结束)。
#0125 ostQuitMessage(0);
#0126 break;
#0127
#0128 default:
#0129 return (DefWindowroc(hWnd, message, waram, laram));
#0130 }
#0131 return (0);
#0132 }
#0133 //---------------------------------------------------------------
#0134 // About - 对话框函数
#0135 //---------------------------------------------------------------
#0136 LRESULT CALLBACK About(HWND hDlg, UINT message,
#0137 WARAM waram, LARAM laram)
#0138 {
#0139 UNREFERENCED_ARAMETER(laram); // 避免编译时的警告
#0140
#0141 switch (message) {
#0142 case WM_INITDIALOG:
#0143 return (TRUE); // TRUE 表示我已处理过这个消息
#0144
#0145 case WM_COMMAND:
#0146 if (LOWORD(waram) == IDOK
#0147 ||LOWORD(waram) == IDCANCEL) {
#0148
EndDialog(hDlg, TRUE);
#0149 return (TRUE); // TRUE 表示我已处理过这个消息
#0150 }
#0151 break;
#0152 }
#0153