vc如何获得windows默认打印机的驱动程序名

wind 2000-02-28 06:03:00
如题
...全文
322 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
redoak2000 2001-10-05
  • 打赏
  • 举报
回复
to dusj(小兔乖乖):
有这一句::)
//在NT中把上面的5全部换成4,详情可查MSDN
dusj 2001-08-30
  • 打赏
  • 举报
回复
redoak2000(小舟一叶)的代码好象只能运行在win 95下。
redoak2000 2000-02-29
  • 打赏
  • 举报
回复
1.MFC:
PRINTDLG printDlg;
GetPrinterDeviceDefaults(&printDlg);
SelectPrinter(printDlg.hDevNames,printDlg.hDevMode);
CreatePrinterDC(g_dcPrinterDC);
2.API: 使用EnumPrinters()
PRINTER_INFO_5 * pinfo5 ;//Win98
EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 5, NULL,
0, &dwNeeded, &dwReturned) ;
pinfo5 = (PRINTER_INFO_5*)malloc (dwNeeded) ;
EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 5, (PBYTE) pinfo5,
dwNeeded, &dwNeeded, &dwReturned) ;
g_sPrnName=pinfo5->pPrinterName;
free (pinfo5) ;
//在NT中把上面的5全部换成4,详情可查MSDN


Jackzhu 2000-02-29
  • 打赏
  • 举报
回复
CWinApp::GetPrinterDeviceDefaults()
第1章 驱动程序开发环境
第2章 测试驱动程序
第一部分 一般内核模式
第1章Windows 2000和WDM驱动程序
第2章 分层的I/O、IRP和I/O对象
第3章 系统定义的对象和对驱动程序的支持
第4章 驱动程序基本结构
第5章DriverEntry 和 Reinitialize 例程
第6章Dispatch例程
第7章StartIo和队列管理例程
第8章 中断服务例程
第9章 DpcForIsr例程和CustomDpc例程
第10章SynchCritSection例程
第11章AdapterControl和ControllerControl例程
第12章Cancel例程
第13章IoCompletion例程
第14章IoTimer和CustomTimerDpc例程
第15章Unload例程
第16章 常见的驱动程序设计问题

第1部分 图形驱动程序
第2部分 显示器及视频微端口驱动程序
第3部分 打印机驱动程序及假脱机打印部件

第五卷 网络驱动程序设计指南 1
第一部分 网络驱动程序 2
第一章 网络驱动程序设计指南的向导 3
第二章 内核模式驱动程序的网络结构 6
2.1 Windows 2000 网络结构和OSI模型 6
2.2 NDIS驱动程序 7
2.2.1 NDIS微端口驱动程序 7
2.2.2 NDIS中间层驱动程序 8
2.2.3 NDIS协议驱动程序 9
2.3 TDI驱动程序 9
2.4 网络驱动程序环境 9
2.4.1 无连接环境的网络驱动程序 10
2.4.2 面向连接环境下的网络驱动程序 10
2.4.3 WAN网络驱动程序的环境 11
第三章 网络驱动程序编程要点 13
3.1 可移植性 13
3.2 多处理器支持 13
3.3 IRQL 14
3.4 同步和指示 14
3.5 包结构 16
3.6 使用共享内存 17
3.7 异步I/O和完成函数 17
第二部分 微端口NIC驱动程序 19
第一章 NDIS NIC微端口驱动程序 20
1.1 NIC微端口驱动程序类型 20
1.2 网络接口卡支持 20
1.3 微端口驱动程序代码的重要特征 22
1.3.1 MiniportXxx函数 22
1.3.2 与NDIS库链接 22
1.3.3 微端口适配器环境 22
1.3.4 VC环境 23
1.3.5 网络OID 23
1.4 驱动程序例子 24
第二章 NIC微端口操作和函数概要 25
2.1 NIC微端口操作 25
2.1.1 初始化NDIS库和注册微端口驱动程序 25
2.1.2 注册网络接口卡 25
2.1.3 对查询和设置微端口信息作出响应 26
2.1.4 产生,激活,去活,和删除虚连接 26
2.1.5 发送数据 27
2.1.5.1 多包发送 27
2.1.5.2 单包发送 28
2.1.6 指示和传递接收的数据 28
2.1.6.1 多包接收 29
2.1.6.2 单包接收 29
2.1.7 指示状态 30
2.1.8 复位网络接口卡 30
2.1.9 终止一个微端口NIC驱动程序 30
2.2 微端口上层函数 30
2.2.1 无连接微端口的上层函数 31
2.2.2 面向连接微端口的上层函数 32
2.3 由微端口调用的NDIS函数 33
2.3.1 NDIS提供的初始化和注册函数 34
2.3.2 NDIS提供的硬件设置函数 35
2.3.3 NDIS提供的I/O端口函数 36
2.3.4 NDIS数据的与DMA相关的函数 37
2.3.5 NDIS提供的中断处理函数 38
2.3.6 NDIS提供的同步函数 38
2.3.7 NDIS提供的状态函数 39
2.3.8 NDIS为无连接微端口提供的发送和接收函数 39
2.3.9 NDIS为面向连接微端口提供的发送和接收函数 40
2.3.10 NDIS提供的带外数据宏 41
2.3.11 NDIS提供的包和缓存处理函数 41
2.3.12 NDIS提供的支持函数 43
2.3.13 NDIS提供的媒体相关宏 46
第三章 NIC微端口驱动程序入口点和初始化 47
3.1 NDIS微端口驱动程序入口函数 47
3.1.1 初始化包裹 47
3.1.2 注册微端口 48
3.1.2.1 指定NDIS版本号 48
3.1.2.2 注册MiniportXxx函数 48
3.1.2.3 为中断支持的注册处理程序 50
3.1.2.4 为无连接微端口选择一个发送函数 51
3.1.2.5 为无连接微端口选择接收函数 51
3.1.2.6 注册一个分配完成处理程序 52
3.1.2.7 注册一个挂起检测(CheckForHang) 处理程序 52
3.2 NDIS微端口初始化 53
3.2.1 注册一个NIC 53
3.2.1.1 分配一个适配器指定的环境区域 54
3.2.1.2 读取配置信息 54
3.2.1.3 注册NIC 54
3.2.2 声明资源 55
3.2.2.1 分配内存 55
3.2.2.2 注册端口 56
3.2.2.3 总线管理器DMA设备初始化 56
3.2.2.4可编程I/O设备初始化 57
3.2.2.5 内存映射设备初始化 58
3.2.2.6 从属DMA设备初始化 58
3.2.3 注册一个中断 59
3.2.4 注册一个关闭函数 59
3.2.5 初始化轮询时钟 59
3.2.6 在初始化当中的同步 60
3.2.7 在初始化时处理错误 60
3.3 查询微端口信息 61
3.4 减少微端口初始化时间 61
第四章 数据传输 64
4.1 中断处理 64
4.2 DPC处理程序 66
4.3 带外(OOB)数据包 66
4.3.1 等待发送的OOB数据 67
4.3.2 接收的OOB数据 68
4.4 发送包 69
4.4.1 无连接微端口的多包传送 70
4.4.1.1 串行微端口的多包传送 70
4.4.1.2 非串行微端口的多包传送 71
4.4.2 无连接微端口的单包发送 71
4.4.3 面向连接微端口的多包发送 72
4.4.4 发送数据前的内存同步 73
4.4.5 发送步骤 74
4.4.5.1 在总线控制器DMA NIC上发送包 74
4.4.5.2 在PIO设备上发送单包 76
4.4.5.3 使用板上内存发送包 77
4.5 非串行微端口 78
4.5.1 非串行微端口的NDIS要求 78
4.5.2 非串行微端口的驱动程序内部要求 78
4.6 接收数据 79
4.6.1 无连接和面向连接微端口的多包接收 79
4.6.2 无连接微端口的单包接收 82
4.6.3 接收数据的高速缓存(Cache)因素 83
4.6.4 接收数据的步骤 83
4.6.4.1 接收期间的包管理 84
4.6.4.2 在总线控制器DMA NIC上接收数据 84
4.6.4.3 在PIO NIC上接收数据 85
4.6.4.4 在内存映射设备上接收数据 85
4.7 保持统计量 85
4.8 802.1P 包的优先权 86
4.8.1 查询802.1p优先权支持 87
4.8.2 802.1优先权的包支持 87
4.8.3 为发送和接收指定包的大小 88
4.8.4 默认情况下禁止802.1p的优先权支持 88
第五章 获取和设置WMI的微端口信息及NDIS支持 89
5.1 NDIS管理信息和OID 89
5.2 查询微端口信息 89
5.2.1 无连接微端口的查询 90
5.2.2 面向连接微端口的查询 91
5.3 设置微端口信息 92
5.3.1 为无连接微端口设置信息 92
5.3.2 为面向连接微端口设置信息 92
5.3.3 设置微端口信息的时机 93
5.4 报告硬件状态 93
5.5 WMI的NDIS支持 94
5.5.1 用WMI注册与注销NDIS微端口 94
5.5.2 OID和微端口状态的GUID映射 94
5.5.3 支持命VC 94
5.5.4 NDIS支持的WMI操作 95
5.5.5 向WMI注册标准微端口OID 95
5.5.6 向WMI注册的标准微端口状态 97
5.5.7 定制OID与状态指示 98
5.5.7.1 填充NDIS_GUID 98
5.5.7.2 包括MOF文件 99
第六章 微端口的电源管理 100
6.1 电源管理的需求与可选的OID 100
6.2 网络设备电源状态 101
6.3 网络唤醒事件 102
6.3.1 连接改变唤醒 102
6.3.2 网络唤醒帧 102
6.3.3 魔包唤醒 103
6.3.4 启用唤醒事件 103
6.3.5 处理唤醒事件 103
6.4 处理OID_PNP_QUERY_POWER 104
6.5 处理OID_PNP_SET_POWER 104
6.5.1 转入睡眠状态 104
6.5.2 转入工作状态 104
6.6 早期微端口的电源管理 105
第七章 重置,停止和关闭 106
7.1 硬件重置(Reset) 106
7.2 停止(Halt)处理程序 106
7.3 关闭(Shutdown)处理程序 107
第八章 广域网微端口 NIC驱动程序 109
8.1 RAS 体系结构 109
8.2 NDISWAN 概述 111
8.3 网络卡、绑定、和连接 113
8.4 广域网微端口驱动程序的实现 114
8.4.1 标准广域网微端口驱动程序与局域网微端口驱动程序的区别 115
8.4.2 CoNDIS广域网微端口驱动程序的附加特性 115
8.4.3 广域网微端口驱动程序提供的服务 116
8.4.3.1 注册为广域网微端口驱动程序 116
8.4.3.2 查询广域网微端口驱动程序的信息 117
8.4.3.3 设置广域网小段口驱动程序的状态 122
8.4.3.4 在广域网微端口驱动程序上发送数据 123
8.4.4 广域网微端口驱动程序做出的指示 125
8.4.4.1 指示从标准广域网微端口驱动程序接收数据 125
8.5 广域网包的组帧 128
8.5.1 异步帧结构 128
8.5.2 X.25帧结构 128
8.5.3 ISDN和Switched-56K帧结构 128
8.6 标准NDIS之上的电话服务扩展 128
8.6.1 NDISTAPI概述 129
8.6.2 线路设备、地址和呼叫 129
8.6.3 设置和查询请求 130
8.6.4 保持状态信息 130
8.6.5 建立句柄 131
8.6.6 TAPI注册 131
8.6.7 TAPI初始化 132
8.6.8 打开线路 133
8.6.9 接受内入呼叫 133
8.6.10 产生TAPI呼叫 134
8.6.11 主动事件处理 135
8.6.12 Line-Up指示 135
8.6.13 关闭呼叫线路 137
8.6.14 NDISTAPI接口 139
8.7 使用支持电话服务的CoNDIS扩展 143
8.7.1 NDPROXY概述 143
8.7.2 CoNDIS TAPI注册 144
8.7.3 CoNDIS TAPI初始化 144
8.7.4 建立外出呼叫 146
8.7.5 接受内入呼叫 147
8.7.6 CoNDIS TAPI关闭 150
8.7.7 语音流对呼叫管理器的要求 151
8.7.7.1 响应OID_CO_TAPI_LINE_CAPS查询 151
8.7.7.2 为外出呼叫指定参数 151
8.7.7.3 为内入呼叫指定参数 152
8.7.8 在面向连接NDIS之上支持电话服务的非广域网专用的扩展 152
第九章 任务卸载 153
9.1 查询任务卸载能力 153
9.1.1 报告NIC的校验和性能 154
9.1.2 报告NIC的IP安全性性能 155
9.1.3 报告NIC的TCP包分段性能 157
9.2 启用任务卸载能力 157
9.3 停用任务卸载能力 158
9.4 访问Per-Packet信息 158
9.5 卸载TCP/IP校验和任务 159
9.6 卸载IP安全任务 161
9.7 卸载大TCP包分段 164
9.8 卸载组合 165
9.9 使用注册表键值激活和禁止任务卸载 166
第十章 负载平衡和失效替换 166
10.1 关于LBFO 167
10.2 指定对LBFO的支持 168
10.3 在微端口驱动程序上实现LBFO 168
10.3.1 初始化微端口束 168
10.3.2 平衡微端口驱动程序的工作量 169
10.3.3 在主微端口失效后提升一个次微端口 169
第十一章 快速转发路径 169
11.1 关于FFP 170
11.1.1 使用一个NIC的FFP 170
11.1.2 使用多个NIC的FFP 170
11.1.3 IP转发 171
11.1.4 FFP和包过滤 171
11.2 NIDS中的FFP支持 172
11.3 为IP转发在微端口实现FFP 172
第十二章 带WDM低级接口的微端口驱动程序 174
12.1 WDM低层微端口 174
12.2 注册WDM低层的微端口函数 174
12.3 初始化WDM低层微端口 175
12.4 发布命令与远程设备通信 176
12.4.1 在总线上发送包 176
12.4.2 在总线上接收包 176
12.5 WDM低层的实现要点 176
12.6 WDM低层的编译标志 177
第十三章 IrDA微端口NIC驱动程序 178
13.1 IrDA微端口驱动程序简述 178
13.2 IrDA体系结构 179
13.3 IrDA协议驱动程序 179
13.4 IrDA介质特征 179
13.4.1 通信连接速度 180
13.4.2 通信连接回转时间 180
13.4.3 接收器同步 181
13.5 IrLAP帧格式 182
13.5.1 帧格式简述 182
13.5.2 帧信息的使用 183
13.5.3 地址成员 183
13.6 IrDA微端口驱动程序包编码方案 183
13.6.1 SIR编码 184
13.6.2 MIR编码 184
13.6.3 FIR编码 184
13.7 发送和接收帧序列 185
13.8 即插即用 185
13.8.1 非即插即用外部串行连接SIR适配器 185
13.8.2 非即插即用内部SIR适配器或者象串口一样错误地呈现于外的内部SIR适配器 186
13.8.3 即插即用外部串行连接SIR适配器 186
13.8.4 即插即用内部SIR适配器 186
13.8.5 非即插即用总线连接FIR适配器 187
13.8.6 即插即用总线连接FIR适配器 187
第三部分NDIS中间层驱动程序和TDI驱动程序 189
第一章 NDIS中间层驱动程序 189
1.1中间层驱动程序的DriverEntry函数 191
1.1.1 注册NDIS中间层驱动程序 191
1.1.1.1注册中间层驱动程序的Miniport 192
1.1.1.2注册中间层驱动程序的协议 194
1.2 中间层驱动程序的动态绑定 196
1.2.1 打开中间层驱动程序下层的适配器 197
1.2.2 微端口初始化 198
1.2.3 中间层驱动程序查询和设置操作 199
1.2.4作为面向连接客户程序注册中间层驱动程序 201
1.3中间层驱动程序数据包管理 203
1.4 中间层驱动程序的限制 205
1.5 中间层驱动程序接收数据 206
1.5.1下边界面向无连接的中间层驱动程序接收数据 206
1.5.2下边界面向连接的中间层驱动程序接收数据 208
1.5.3向高层驱动程序指示接收数据包 209
1.6通过中间层驱动程序传输数据包 210
1.6.1传递介质相关信息 211
1.7处理中间层驱动程序的PnP事件和PM事件 212
1.7.1处理OID_PNP_XXX查询和设置 213
1.7.2中间层驱动程序ProtocolPnPEvent处理程序的实现 214
1.7.3处理规定的电源请求 214
1.8中间层驱动程序复位操作 215
1.9中间层驱动程序拆除绑定操作 216
1.10中间层驱动程序状态指示 217
第二章 NDIS协议驱动程序 219
2.1 协议DriverEntry及其初始化 220
2.1.1注册NDIS协议驱动程序 220
2.1.2 打开中间层驱动程序低层的适配器 223
2.1.3 协议驱动程序查询和设置操作 224
2.1.4作为呼叫管理器或者面向连接客户程序进行注册 225
2.2 协议驱动程序数据包管理 229
2.3 协议驱动程序的动态绑定 230
2.4 协议驱动程序接收数据 231
2.4.1下边界面向无连接的中间层驱动程序接收数据 231
2.4.1.1 在中间层驱动程序中实现ProtocolReceivePacket处理程序 232
2.4.1.2 在协议驱动程序中实现ProtocolReceive处理程序 233
2.4.1.3 从面向无连接协议驱动程序中访问OOB数据信息 234
2.4.2 面向连接协议驱动程序接收数据 234
2.4.2.1 ProtocolCoReceivePacket处理程序实现 235
2.4.2.2 从面向连接协议驱动程序中访问OOB数据信息 235
2.5 发送协议驱动程序创建的数据包 236
2.5.1 从面向无连接协议驱动程序发送数据包 236
2.5.1.1面向无连接协议驱动程序传递介质相关信息 237
2.5.2 面向连接协议驱动程序发送数据包 238
2.5.2.1面向连接协议驱动程序传递介质相关信息 238
2.6处理协议驱动程序的PnP事件和PM事件 239
2.7协议驱动程序复位操作 240
2.8协议驱动程序拆除绑定操作 241
2.9协议驱动程序状态指示 241
第三章 TDI传输器及其客户 243
3.1 传输驱动程序接口(TDI) 243
3.2 TDI设备对象 245
3.3 TDI文件对象 246
3.3.1代表传输地址的文件对象 247
3.3.2代表连接端点的文件对象 247
3.3.3代表控制信道的文件对象 248
3.4 TDI传输驱动程序例程 248
3.5 TDI核心模式客户交互 249
3.6 TDI请求及事件 250
第四章 TDI例程、宏和回调 251
4.1 TDI驱动程序初始化 251
4.1.1 注册TDI传输驱动程序 252
4.1.2 卸载和注销TDI传输驱动程序 252
4.2 TDI驱动程序调度例程 253
4.3 TDI IOCTL请求 254
4.4 TDI 客户回调 255
4.5 TDI 库函数和宏 257
第五章 TDI操作 260
5.1打开传输地址 260
5.2打开连接端点 261
5.3打包并提交IOCTL请求 262
5.4设置和查询信息 262
5.5建立端端连接 263
5.6发送和接收面向连接数据 264
5.7发送和接收无连接数据 266
5.8面向连接和面向无连接传输 267
5.9请求传输相关操作 268
5.10接收错误通知 268
5.11断开端端连接 268
5.12关闭连接端点 269
5.13关闭传输地址和控制信道 269
第六章Windows Sockets的传输助手DLLS 271
6.1 Windows Sockets Helper DLL结构 271
6.2用WSH DLL通信 271
6.3配置WSH DLL 272
6.4WSH DLL同步 272
6.5用WSH DLL支持连接和断开数据 273
6.5.1客户应用程序和连接数据 273
6.5.2服务器应用程序和连接数据 273
6.5.3断连(disconnect)数据 274
6.6WSH DLL函数总览 274
第四部分面向连接的网络驱动程序接口标准(NDIS) 276
第一章 面向连接的网络驱动程序接口标准(NDIS) 276
1.1面向连接环境 276
1.2使用AFs,VCs,SAP和Parties 277
1.2.1地址族 277
1.2.2虚连接 277
1.2.3 SAPs 278
1.2.4 Parties 278
1.3服务质量 278
1.4MCM和呼叫管理器有何不同 278
1.4.1初始化的不同 279
1.4.2对NdisXxx函数调用的不同 279
1.4.3虚连接的不同 279
1.5面向连接的时间特性 280
1.6面向连接操作 280
1.6.1面向连接操作总结 280
1.6.1.1由客户执行的面向连接操作 280
1.6.1.2由呼叫管理器执行的面向连接操作 281
1.6.1.3由微端口执行的面向连接操作 282
1.6.2地址族和SAPs上的操作 283
1.6.2.1注册并打开一个地址族 283
1.6.2.2注册一个SAP 284
1.6.2.3注销SAP 285
1.6.2.4关闭一个地址族 285
1.6.3 VCs上的操作 286
1.6.3.1创建VC 286
1.6.3.2激活VC 287
1.6.3.3使VC去活 288
1.6.3.4删除VC 289
1.6.4创建呼叫 289
1.6.4.1进行呼叫 290
1.6.4.2指示内入呼叫 291
1.6.5改变活动VC的QoS 292
1.6.5.1客户发起的改变呼叫参数请求。 292
1.6.5.2改变呼叫参数的内入请求 293
1.6.6增加和删除Parties 293
1.6.6.1把一个Party加入到多点呼叫 293
1.6.6.2从多点呼叫中删除Party 294
1.6.6.3从多点呼叫中删除一个Party的内入请求 295
1.6.7发送并接收数据 295
1.6.7.1在VC上发送包 295
1.6.7.2接收VC上的包 296
1.6.8断开呼叫 297
1.6.8.1客户发起的关闭呼叫请求 297
1.6.8.2关闭呼叫的内入请求 298
1.6.9获取并设置信息 298
1.6.9.1查询或设置信息 298
1.6.9.2指示微端口状态 299
1.6.10重置 299
第五部分 安装网络组件 301
第一章 安装网络组件 301
1.1用于安装网络组件的组件和文件 301
1.2创建网络INF文件 302
1.2.1网络INFS文件的约定 302
1.2.2网络INF文件的版本节 302
1.2.3网络INF文件的模型节 303
1.2.4 INF文件的DDInstall节 304
1.2.5删除节 306
1.2.6 ControlFlags节 306
1.2.7网络INF文件的add-registry-sections 306
1.2.7.1设置静态参数 307
1.2.7.2 为WAN适配器说明WAN端点 307
1.2.7.3为ISDN适配器说明ISDN键和值 307
1.2.7.4安装多协议WAN NICs 309
1.2.7.5请求安装另一个网络组件 310
1.2.7.6说明NetCLient组件的字和提供者 310
1.2.7.7增加HelpText值 311
1.2.7.8为通知对象增加注册值 311
1.2.7.9向Ndi键增加服务相关值 311
1.2.7.10说明绑定接口 312
1.2.7.11为高级属性页说明配置参数 314
1.2.7.12为网络适配器说明定制属性页 315
1.2.7.13说明过滤器服务值 315
1.2.7.14说明束成员关系 317
1.2.7.15 Window 2000中不用的 Window 95/98 Ndi值和键 317
1.2.8 DDInstall.Service节 318
1.2.9 NetworkProrider和PrintProvider节 318
1.2.9.1包含一个NetworkProvider节 319
1.2.9.2 包括一个PrintProvider节 319
1.2.10 Winsock节 320
1.2.11网络组件安装需求总结 322
1.2.11.1网络适配器的安装需求 322
1.2.11.2网络协议安装要求 323
1.2.11.3中间层网络驱动程序的安装需求 324
1.2.11.4网络过滤器驱动程序的安装需求 325
1.2.11.5网络客户的安装需求 326
1.2.11.6网络服务的安装请求 327
第二章 网络组件的通知对象 328
2.1关于通知对象 328
2.1.1 通知对象图 329
2.1.2通知类型 329
2.1.3网络组件的安装 329
2.1.4删除网络组件 330
2.1.5升级网络组件 330
2.1.6显示并改变属性 330
2.1.7网络配置 331
2.2创建通知对象 331
2.2.1装载通知对象DLL和类对象 331
2.2.2定义通知对象 332
2.2.3创建并初始化通知对象实例 332
2.2.4安装,升级和删除组件 333
2.2.5为组件生成属性页 333
2.2.6设置环境来显示属性 334
2.2.7评价网络配置的变化 334
2.2.8将组件变化加入注册表 335
2.2.9配置组件驱动程序 335

4. API之打印函数 AbortDoc 取消一份文档的打印 AbortPrinter 删除与一台打印机关联在一起的缓冲文件 AddForm 为打印机的表单列表添加一个新表单 AddJob 用于获取一个有效的路径,以便用它为作业创建一个后台打印文件。它也会为作业分配一个作业编号 AddMonitor 为系统添加一个打印机监视器 AddPort 启动"添加端口"对话框,允许用户在系统可用端口列表中加入一个新端口 AddPrinter 在系统中添加一台新打印机 AddPrinterConnection 连接指定的打印机 AddPrinterDriver 为指定的系统添加一个打印驱动程序 AddPrintProcessor 为指定的系统添加一个打印处理器 AddPrintProvidor 为系统添加一个打印供应商 AdvancedDocumentProperties 启动打印机文档设置对话框 ClosePrinter 关闭一个打开的打印机对象 ConfigurePort 针对指定的端口,启动一个端口配置对话框 ConnectToPrinterDlg 启动连接打印机对话框,用它同访问网络的打印机连接 DeleteForm 从打印机可用表单列表中删除一个表单 DeleteMonitor 删除指定的打印监视器 DeletePort 启动"删除端口"对话框,允许用户从当前系统删除一个端口 DeletePrinter 将指定的打印机标志为从系统中删除 DeletePrinterConnection 删除与指定打印机的连接 DeletePrinterDriver 从系统删除一个打印机驱动程序 DeletePrintProcessor 从指定系统删除一个打印处理器 DeletePrintProvidor 从系统中删除一个打印供应商 DeviceCapabilities 利用这个函数可获得与一个设备的能力有关的信息 DocumentProperties 打印机配置控制函数 EndDocAPI 结束一个成功的打印作业 EndDocPrinter 在后台打印程序的级别指定一个文档的结束 EndPage 用这个函数完成一个页面的打印,并准备设备场景,以便打印下一个页 EndPagePrinter 指定一个页在打印作业中的结尾 EnumForms 枚举一台打印机可用的表单 EnumJobs 枚举打印队列中的作业 EnumMonitors 枚举可用的打印监视器 EnumPorts 枚举一个系统可用的端口 EnumPrinterDrivers 枚举指定系统中已安装的打印机驱动程序 EnumPrinters 枚举系统中安装的打印机 EnumPrintProcessorDatatypes 枚举由一个打印处理器支持的数据类型 EnumPrintProcessors 枚举系统中可用的打印处理器 Escape 设备控制函数 FindClosePrinterChangeNotification 关闭用FindFirstPrinterChangeNotification函数获取的一个打印机通告对象 FindFirstPrinterChangeNotification 创建一个新的改变通告对象,以便我们注意打印机状态的各种变化 FindNextPrinterChangeNotification 用这个函数判断触发一次打印机改变通告信号的原因 FreePrinterNotifyInfo 释放由FindNextPrinterChangeNotification函数分配的一个缓冲区 GetForm 取得与指定表单有关的信息 GetJob 获取与指定作业有关的信息 GetPrinter 取得与指定打印机有关的信息 GetPrinterData 为打印机设置注册表配置信息 GetPrinterDriver 针对指定的打印机,获取与打印机驱动程序有关的信息 GetPrinterDriverDirectory 判断指定系统中包含了打印机驱动程序的目录是什么 GetPrintProcessorDirectory 判断指定系统中包含了打印机处理器驱动程序及文件的目录 OpenPrinter 打开指定的打印机,并获取打印机的句柄 PrinterMessageBox 在拥有指定打印作业的系统上显示一个打印机出错消息框 PrinterProperties 启动打印机属性对话框,以便对打印机进行配置 ReadPrinter 从打印机读入数据 ResetDC 重设一个设备场景 ResetPrinter 改变指定打印机默认数据类型及文档设置 ScheduleJob 提交一个要打印的作业 SetAbortProc 为Windows指定取消函数的地址 SetForm 为指定的表单设置信息 SetJob 对一个打印作业的状态进行控制 SetPrinter 对一台打印机的状态进行控制 SetPrinterData 设置打印机的注册表配置信息 StartDoc 开始一个打印作业 StartDocPrinter 在后台打印的级别启动一个新文档 StartPage 打印一个新页前要先调用这个函数 StartPagePrinter 在打印作业中指定一个新页的开始 WritePrinter 将发送目录中的数据写入打印机 5. API之文本和字体函数 AddFontResource 在Windows系统中添加一种字体资源 CreateFont 用指定的属性创建一种逻辑字体 CreateFontIndirect 用指定的属性创建一种逻辑字体 CreateScalableFontResource 为一种TureType字体创建一个资源文件,以便能用API函数AddFontResource将其加入Windows系统 DrawText 将文本描绘到指定的矩形中 DrawTextEx 与DrawText相似,只是加入了更多的功能 EnumFontFamilies 列举指定设备可用的字体 EnumFontFamiliesEx 列举指定设备可用的字体 EnumFonts 列举指定设备可用的字体 ExtTextOut 经过扩展的文本描绘函数。也请参考SetTextAlign函数 GetAspectRatioFilterEx 用SetMapperFlags要求Windows只选择与设备当前纵横比相符的光栅字体时,本函数可判断纵横比大小 GetCharABCWidths 判断TureType字体中一个或多个字符的A-B-C大小 GetCharABCWidthsFloat 查询一种字体中一个或多个字符的A-B-C尺寸 GetCharacterPlacement 该函数用于了解如何用一个给定的字符显示一个字串 GetCharWidth 调查字体中一个或多个字符的宽度 GetFontData 接收一种可缩放字体文件的数据 GetFontLanguageInfo 返回目前选入指定设备场景中的字体的信息 GetGlyphOutline 取得TureType字体中构成一个字符的曲线信息 GetKerningPairs 取得指定字体的字距信息 GetOutlineTextMetrics 接收与TureType字体内部特征有关的详细信息 GetRasterizerCaps 了解系统是否有能力支持可缩放的字体 GetTabbedTextExtent 判断一个字串占据的范围,同时考虑制表站扩充的因素 GetTextAlign 接收一个设备场景当前的文本对齐标志 GetTextCharacterExtra 判断额外字符间距的当前值 GetTextCharset 接收当前选入指定设备场景的字体的字符集标识符 GetTextCharsetInfo 获取与当前选定字体的字符集有关的详细信息 GetTextColor 判断当前字体颜色。通常也称为"前景色" GetTextExtentExPoint 判断要填入指定区域的字符数量。也用一个数组装载每个字符的范围信息 GetTextExtentPoint 判断一个字串的大小(范围) GetTextFace 获取一种字体的字样 GetTextMetrics 获取与选入一种设备场景的物理字体有关的信息 GrayString 描绘一个以灰色显示的字串。通常由Windows用于标识禁止状态 PolyTextOut 描绘一系列字串 RemoveFontResource 从Windows系统中删除一种字体资源 SetMapperFlags Windows对字体进行映射时,可用该函数选择与目标设备的纵横比相符的光栅字体 SetTextAlign 设置文本对齐方式,并指定在文本输出过程中使用设备场景的当前位置 SetTextCharacterExtra 描绘文本的时候,指定要在字符间插入的额外间距 SetTextColor 设置当前文本颜色。这种颜色也称为"前景色" SetTextJustification 通过指定一个文本行应占据的额外空间,可用这个函数对文本进行两端对齐处理 TabbedTextOut 支持制表站的一个文本描绘函数 TextOut 文本绘图函数 6. API之菜单函数 AppendMenu 在指定的菜单里添加一个菜单项 CheckMenuItem 复选或撤消复选指定的菜单条目 CheckMenuRadioItem 指定一个菜单条目被复选成"单选"项目 CreateMenu 创建新菜单 CreatePopupMenu 创建一个空的弹出式菜单 DeleteMenu 删除指定的菜单条目 DestroyMenu 删除指定的菜单 DrawMenuBar 为指定的窗口重画菜单 EnableMenuItem 允许或禁止指定的菜单条目 GetMenu 取得窗口中一个菜单的句柄 GetMenuCheckMarkDimensions 返回一个菜单复选符的大小 GetMenuContextHelpId 取得一个菜单的帮助场景ID GetMenuDefaultItem 判断菜单中的哪个条目是默认条目 GetMenuItemCount 返回菜单中条目(菜单项)的数量 GetMenuItemID 返回位于菜单中指定位置处的条目的菜单ID GetMenuItemInfo 取得(接收)与一个菜单条目有关的特定信息 GetMenuItemRect 在一个矩形中装载指定菜单条目的屏幕坐标信息 GetMenuState 取得与指定菜单条目状态有关的信息 GetMenuString 取得指定菜单条目的字串 GetSubMenu 取得一个弹出式菜单的句柄,它位于菜单中指定的位置 GetSystemMenu 取得指定窗口的系统菜单的句柄 HiliteMenuItem 控制顶级菜单条目的加亮显示状态 InsertMenu 在菜单的指定位置处插入一个菜单条目,并根据需要将其他条目向下移动 InsertMenuItem 插入一个新菜单条目 IsMenu 判断指定的句柄是否为一个菜单的句柄 LoadMenu 从指定的模块或应用程序实例中载入一个菜单 LoadMenuIndirect 载入一个菜单 MenuItemFromPoint 判断哪个菜单条目包含了屏幕上一个指定的点 ModifyMenu 改变菜单条目 RemoveMenu 删除指定的菜单条目 SetMenu 设置窗口菜单 SetMenuContextHelpId 设置一个菜单的帮助场景ID SetMenuDefaultItem 将一个菜单条目设为默认条目 SetMenuItemBitmaps 设置一幅特定位图,令其在指定的菜单条目中使用,代替标准的复选符号(√) SetMenuItemInfo 为一个菜单条目设置指定的信息 TrackPopupMenu 在屏幕的任意地方显示一个弹出式菜单 TrackPopupMenuEx 与TrackPopupMenu相似,只是它提供了额外的功能 作者Blog:http://blog.csdn.net/daiguopeng/ 相关文章 用VC 6.0实现串行通信的三种方法 windows运行命令详解 Windows API函数大全四 Windows API函数大全三 Windows API函数大全二
第一部分 程序员必读 第一章 对程序错误的处理 在我们开始介绍Microsoft Windows应该提供的许多特性之前,我们首先必须了解Windows的各个函数是如何进行错误处理的。 当你调用一个Windows函数时,它首先要检验你传递给它的的各个参数的有效性,然后再设法执行它的任务。如果你传递了一个无效参数,或者由于某种原因它无法执行这项操作,那么该函数就会返回一个值,指明该函数在某种程度上运行失败了。表1-1列出了大多数Windows函数使用的数据类型的返回值。 表1-1 Windows函数常用的返回值类型 数据类型 表示失败的值 VOID 该函数的运行不可能失败。Windows函数的返回值类型很少 是VOID。 BOLL 如果函数运行失败,那么返回值是0,否则返回的是非0值。最 好对返回值进行测试,以确定它是0还是非0。如果它是TRUE ,则不要测试返回值。 HANDLE 如果函数运行失败,则返回值通常是NULL,否则返回值为 HANDLE,,用于标识你可以操作的一个对象。对于这个返回 值,你应该小心处理,因为有些函数会返回一个句柄 值INVALID_HANDLE_VALUE,它被定义为-1。该函数的 Platform SDK资料将会清楚地说明该函数是返回NULL还 是INVALID_HANDLE_VALID,以便指明函数运行已经失败。 PVOID 如果函数运行失败,则返回值是NULL,否则返回PVOID,以 标识数据块的内存地址。 LONG/DWORD 这是个难以处理的值。返回数量的函数通常返回LONG 或DWORD。如果由于某种原因,函数无法对你想要进行计数 的对象进行计数,那么该函数通常返回0或-1(根据该函数而定) 。如果你调用的函数返回了LONG/DWORD,那么请认真阅 读Platform SDK资料,以确保你能正确检查潜在的错误。 当一个Windows函数返回一个错误代码时,它常常可以用来了解函数为什么会运行失败。Microsoft公司编译了一个所有可能的错误代码的列表,并且为每个错误代码分配了一个32位的号码。 从系统内部来讲,当一个Windows函数检测到一个错误时,它会使用一个称为线程本地存储器的机制,将相应的错误代码号码与调用的线程关联起来。(“线程本地存储器”将在第21章中介绍)。这将使线程能够互相独立地运行,而不会影响各自的错误代码。当函数返回给你时,它的返回值就能指明一个错误已经发生。若要确定这是个什么错误,请调用GetLastError函数: 见原书P4的程序(1) 该函数只返回线程的32位错误代码。 当你拥有32位错误代码的号码时,你必须将该号码转换成更有用的某种对象。WinError.h头文件包含了Microsoft公司定义的错误代码的列表。下面我显示了该列表的某些内容,使你能够看到它的大概样子: 见原书P4的程序(2)和P5的程序 你可以看到,每个错误都有3种表示法:即一个消息ID(这是你可以在源代码中使用的一个宏,以便与GetLastError的返回值进行比较),消息文本(对错误的英文描述)和一个号码(你应该避免使用这个号码,而应该使用消息ID)。请记住,我只选择了WinError.h头文件中的很少一部分内容来向你进行展示,整个文件的长度超过21000行。 当Windows函数运行失败时,你应该立即调用GetLastError函数,否则,如果你调用另一个Windows函数,它的值很可能被改写。 说明 GetLastError能返回线程产生的最后一个错误。如果该线程调用的Windows 函数运行成功,那么最后一个错误代码就不被改写,并且不指明运行成功。有少 数Windows函数并不遵循这一规则,并且它会更改最后的错误代码,但是Platform SDK资料通常指明,当函数运行成功时,该函数会更改最后的错误代码。 Windows 98 许多Windows 98的函数实际上是用Microsoft公司的16位Windows 3.1产 品产生的16位代码来实现的。这种比较老的代码并不通过GetLastError之类函 数来报告错误,而且Microsoft公司并没有在Windows 98中修改16位代码,以 支持这种错误处理方式。对于我们来说,这意味着Windows 98中的许多Win32 函数在运行失败时不能设置最后的错误代码。该函数将返回一个值,指明运行失 败,这样你就能够发现该函数确实已经运行失败。但是你无法确定运行失败的原 因。 有些Windows函数之所以能够成功运行,那是若干个原因产生的结果。例如,创建指明的事件内核对象之所以能够取得成功,原因是你实际上创建了该对象,或者是因为已经存在带有相同字的事件内核对象。你的应用程序必须知道成功的原因。为了将该信息返回给你,Microsoft公司选择使用最后错误代码机制。这样,当某些函数运行成功时,你就能够通过调用GetLadtError函数来确定其他的一些信息。对于具有这种行为特性的函数来说,Platform SDK资料清楚地说明了GetLastError函数可以这样来使用。请参见该资料,以便找出CreateEvent函数的例子。 当你进行调试的时候,我发现监控线程的最后错误代码是非常有用的。在Microsoft Visual studio 6.0中,Microsoft的调试程序支持一个非常有用的特性,即你可以配置Watch窗口,以便始终都能向你显示线程的最后错误代码的号码和该错误的英文描述。通过选定Watch窗口中的一行,并键入“@err,hr",你就能够做到这一点。观察图1-1,你会看到我已经调用了CreateFile函数。该函数返回INVALID_HANDLE_VALUE(-1)的HANDLE,表示它未能打开指定的文件。但是Watch窗口向我们显示最后错误代码(即如果我调用GetLastErro函数,该函数返回的错误代码)是0x00000002。该Watch窗口又进一步指明错误代码2是指“系统不能找到指定的文件。”你会发现它与WinError.h头文件中的错误代码2所指的字符串是相同的。 图1-1 在Visual Studio 6.0的Watch窗口中键入 “@err,hr",你就可以查看当前线程的最后错误代码。 Visual studio还配有一个小的实用程序,称为Error Lookup。你可以使用Error Lookup将错误代码的号码转换成它的文本描述。 见P7的Error Lookup插图 如果我在我编写的应用程序中发现一个错误,我可能想要向用户显示该错误的文本描述。Windows提供了一个函数,可以将错误代码转换成它的文本描述。该函数称为FormatMessage。请看下面的代码: 见原书P8的程序(1) FormatMessage函数的功能实际上是非常丰富的,在创建向用户显示的字符串信息时,它是人们首选的函数。该函数之所以有这样大的作用,原因之一是它很容易用多种语言来进行操作。该函数能够检测出用户首选的语言(在Regional Settings Control Panel小应用程序中设定),并返回相应的文本。当然,你首先必须自己转换字符串,然后将已转换的消息表资源嵌入你的.exe文件或DLL模块,不过,这时该函数会选定正确的嵌入对象。ErrorShow示例应用程序(本章后面将加以介绍)展示了如何调用该函数,以便将Microsoft公司定义的错误代码转换成它的文本描述。 有些人常常问我,Microsoft公司是否建立了一个主控列表,以显示每个Windows函数可能返回的所有错误代码。可惜,答案是没有这样的列表,而且Microsoft公司将永远不会建立这样的一个列表。因为在创建系统的新版本时,建立和维护该列表实在太困难了。 建立这样一个列表时存在的问题是,你可以调用一个Windows函数,但是该函数能够在内部调用另一个函数,而这另一个函数又可以调用另一个函数,如此类推。由于各种不同的原因,这些函数中的任何一个函数都可能运行失败。有时,当一个函数运行失败时,较高级的函数对它进行恢复,并且仍然可以执行你想执行的操作。为了创建该主控列表,Microsoft公司必须跟踪每个函数的运行路径,并建立所有可能的错误代码的列表。这项工作很困难。当创建系统的新版本时,这些函数的运行路径就会改变。 1.1 你也能够定义自己的错误代码 好了,我已经说明Windows函数是如何向函数的调用者指明发生的错误。Microsoft公司也使你能够将该机制用于你自己的函数。比如说,你编写了一个你希望其他人调用的函数。你的函数可能因为这样或那样的原因而运行失败,你必须向函数的调用者说明它已经运行失败。 若要指明函数运行失败,你只需要设定线程的最后的错误代码,然后让你的函数返回FALSE,INVALID_HANDLE_VALUE,NULL,或者返回任何合适的信息。若要设定线程的最后错误代码,你只需要调用下面的代码: 见原书P8的程序(2) 请将你认为合适的任何32位号码传递给该函数。我设法使用WinError.h中已经存在的代码,只要该代码能够正确地指明我想要报告的错误即可。如果你认为WinError.h中的任何代码都不能正确地反映该错误的性质,那么你可以创建你自己的代码。错误代码是个32位的数字,它可以划分成下表所示的各个域。 位 31-30 29 28 27-16 15-0 内容 严重性 Microsoft/ 保留 设备代码 异常代码 客户 含义 0=成功 0=Microsoft 必须是0 由Microsoft 由Microsoft/ 1=供参考 公司定义的 公司定义 客户定义 2=警告 代码 3=错误 1=客户定义 的代码 这些域将在第24章中详细讲述。现在,你需要知道的重要域是第29位的信息。Microsoft公司规定,他们建立的所有错误代码的这个信息位均使用0。如果你创建自己的错误代码,你必须在这个信息位中输入1。这样,就可以确保你的错误代码与Microsoft公司目前或者将来定义的错误代码不会发生冲突, 1.2 ErrorShow示例应用程序 ErrorShow应用程序“01 ErrorShow.exe"(在图1-2中列出)展示了如何获取错误代码的文本描述的方法。该应用程序的源代码和资源文件位于本书所附光盘上的01-ErrorShow目录下。一般来说,该应用程序用于显示调试程序的Watch窗口和Error Lookup程序是如何运行的。当你启动该程序时,就会出现下面这个窗口。 见原书P9的插图 你可以将任何错误代码键入该编辑控件。当你单击Look Up按钮时,在底部的滚动窗口中就会显示该错误的文本描述。该应用程序唯一令人感兴趣的特性是如何调用FormatMessage函数。下面是我使用该函数的方法: 见原书P10的程序(1) 第一个代码行用于从编辑控件中检索错误代码的号码。然后,建立一个内存块的句柄并将它初始化为NULL。FormatMessage函数在内部对内存块进行分配,并将它的句柄返回给我们。 当调用FormatMessage函数时,我传递了FORMAT_MESSAGE_FROM_SYSTEM标志。该标志告诉FormatMessage函数,我们想要系统定义的错误代码的字符串。我还传递了FORMAT_MESSAGE_ALLOCATE_BUFFER标志,告诉该函数为错误代码的文本描述分配足够大的内存块。该内存块的句柄将在hlocal变量中返回。第三个参数指明我们想要查找的错误代码的号码,第四个参数指明我们想要文本描述使用什么语言。 如果FormatMessage函数运行成功,那么错误代码的文本描述就位于内存块中,我将它拷贝到对话框底部的滚动窗口中。如果FormatMesage函数运行失败,我设法查看NetMsg.dll模块中的消息代码,以了解该错误是否与网络有关。使用NetMsg.dll模块的句柄,我再次调用FormatMessage函数。你会看到,每个DLL(或.exe)都有它自己的一组错误代码,你可以使用Message Compiler(MC.exe)将这组错误代码添加给该模块,并将一个资源添加给该模块。这就是Visual Studio的Error Lookup工具允许你用Modules对话框进行的操作。 图1-2 ErrorShow示例应用程序 见原书P11—16 第2章 UNICODE 随着Microsoft公司的Windows操作系统在全世界日益广泛的流行,对于我们这些软件开发人员来说,将我们的目标瞄准国际上的各个不同市场,已经成为一个越来越重要的问题。美国的软件版本比国际版本提前6个月推向市场,这曾经是个司空见惯的现象。但是,由于各国对Windows操作系统提供了越来越多的支持,因此就更加容易为国际市场生产各种应用软件,从而缩短了软件的美国版本与国际版本推出的时间间隔。 Windows操作系统始终不逾地提供各种支持,以帮助软件开发人员进行应用程序的本地化工作。应用软件可以从各种不同的函数中获得特定国家的信息,并可观察控制面板的设置,以确定用户的首选项。Windows甚至支持不同的字体,以适应我们的应用的需要。 我之所以将这一章放在本书的开头,是因为我考虑到Unicode是开发任何应用程序时要采用的基本步骤。关于Unicode的问题,我在本书的每一章中几乎都要讲到,而且本书中给出的所有示例应用程序都是“用Unicode实现的”。如果你为Microsoft Windows 2000或Microsoft Windows CE开发应用程序,你应该使用Unicode进行开发。如果你为Microsoft Windows 98开发应用程序,你必须对某些问题作出决定。本章也要讲述Windows 98的有关问题。 2.1 字符集 软件的本地化要解决的真正问题,实际上就是如何来处理不同的字符集。多年来,我们许多人一直将文本串作为一系列单字节字符来进行编码,并在结尾处放上一个零。对于我们来说,这已经成了习惯。当我们调用strlen函数时,它在以0结尾的单字节字符数组中返回字符的数目。 问题是,有些文字和书写规则(比如日文中的汉字就是个典型的例子)的字符集中的符号太多了,因此单字节(它提供的符号最多不能超过256个)是根本不敷使用的。为此我们创建了双字节字符集(DBCS),以支持这些文字和书写规则。 2.1.1 单字节与双字节字符集 在双字节字符集中,字符串中的每个字符可以包含一个字节,也可以包含两个字节。例如,日文中的汉字,如果第一个字符在0x81与0x9F之间,或者在0xE0与0xFC之间,那么你就必须观察下一个字节,才能确定字符串中的这个完整的字符。如果要使用双字节字符集,对于程序员来说简直是个很大的难题,因为有些字符只有一个字节宽,而有些字符则是两个字节宽。 如果只是调用strlen函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。ANSI的C运行期库中没有配备相应的函数,使你能够对双字节字符集进行操作。但是,Microsoft Visual C++的运行期库却包含许多函数,如_mbslen,它可以用来操作多字节(既包括单字节也包括双字节)字符串。 为了帮助你对DBCS字符串进行操作,Windows提供了下面的一组帮助函数。 函数 描述 PTSTR CharNext 返回字符串中的下一个字符的地址 (PCTSTR pszCurrentChar); PTSTR CharPrev 返回字符串中的上一个字符的地址 (PCTSTR pszStart, PCTSTR pszCurrentChar); BOOL IsDBCSLendByte 如果该字节是DBCS字符的第一个字节,则返 (BYTE bTestChar); 回TRUE 2.1.2 Unicode:宽字节字符集 Unicode是Apple和Xerox公司于1988年建立的一个技术标准。1991年,成立了一个集团机构负责Unicode的开发和推广应用。该集团由Apple、Compaq、HP、IBM、Microsoft、Oracle、Silicon Graphics、Sybase、Unisys和Xerox等公司组成。(若要了解该集团的全部成员,请通过网址www.Unicode.org查找。)该集团公司负责维护Unicode标准。Unicode的完整描述可以参阅AddisonWesley出版的《Unicode Standard》一书。(该书可以通过网址www.Unicode.org订购。) Unicode提供了一种简单而又一致的表示字符串的方法。Unicode字符串中的所有字符都是16位的字符(两个字节)。它没有专门的字节来指明下一个字节是属于同一个字符的组成部分,还是一个新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符。你不再需要调用CharNext,CharPrev和IsDBCSLeadByte之类的函数。 由于Unicode用一个16位的值来表示每个字符,因此总共可以得到65000个字符,这样,它就能够对世界各国的书面文字中的所有字符进行编码。这远远超过了单字节字符集的256个字符的数目。 目前,已经为阿拉伯文、中文拼音、西里尔字母(俄文)、希腊文、西伯莱文、日文、韩文和拉丁文(英文)字母定义了Unicode代码点1。这些字符集中还包含了大量的标点符号、数学符号、技术符号、箭头、装饰标志、区分标志和其他许多字符。如果你将所有这些字母和符号加在一起,总计约达35000个不同的代码点,这样,总计的65000个代码点中,大约还有一半可供将来扩充时使用。 这65536个字符可以分成不同的区域。下面这个表显示了一部分这样的区域以及分配给这些区域的字符。 16位代码 字符 16位代码 字符 0000-007F ASCII 0300-036F 通用区分标志 0080-00FF 拉丁文1字符 0400-04FF 西里尔字母 0100-017F 欧洲拉丁文 0530-058F 亚美尼亚文 0180-01FF 扩充拉丁文 0590-05FF 西伯莱文 0250-02AF 标准拼音 0600-06FF 阿拉伯文 02B0-02FF 修改型字母 0900-097F 梵文 注1. 代码点是指字符集中的一个符号的位置 目前尚未分配的代码点大约还有29000个,不过它们是保留供将来使用的。另外,大约有6000个代码点是保留供你个人使用的。 2. 2 为何应该使用Unicode 当你开发应用程序时,你当然应该考虑利用Unicode的优点。即使现在你不打算对你的应用程序进行本地化,开发时将Unicode放在心上,肯定可以简化将来的代码转换工作。此外,Unicode还具备下列功能: * 可以很容易地在不同语言之间进行数据交换 * 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件 * 提高你的应用程序的运行效率(本章后面还要详细介绍) 2.3 Windows 2000与Unicode Windows 2000是使用Unicode从头进行开发的,用于创建窗口、显示文本、进行字符串操作等的所有核心函数都需要Unicode字符串。如果你调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果你希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然,进行这些字符串的转换需要占用系统的时间和内存开销。 例如,如果你调用CreateWindowEx函数,并传递类字和窗口标题文本的非Unicode字符串,那么CreateWindowEx必须分配内存块(在你的进程的默认堆中),将非Unicode字符串转换成Unicode字符串,并将结果存储在分配到的内存块中,然后调用Unicode版本的CreateWindowEx函数。 对于用字符串填入缓存的函数来说,系统必须首先将Unicode字符串转换成非Unicode字符串,然后你的应用程序才能处理该字符串。由于系统必须执行所有这些转换操作,因此你的应用程序需要更多的内存,并且运行的速度比较慢。通过从头开始用Unicode来开发应用程序,你就能够使你的应用程序更加有效地运行。 2. 4 Windows 98与Unicode Windows 98不是一种全新的操作系统。它继承了16位Windows操作系统的特性,它不是用来处理Unicode。如果要增加对Unicode的支持,其工作量非常大,因此在该产品的特性列表中没有包括这个支持项目。由于这个原因,Windows 98象它的前任产品一样,几乎都是使用ANSI字符串来进行所有的内部操作的。 你仍然可以编写用于处理Unicode字符和字符串的Windows应用程序,不过,使用Windows函数要难得多。例如,如果你想要调用CreateWindowEx函数并将ANSI字符串传递给它,这个调用的速度非常快,不需要从你进程的默认堆栈中分配缓存,也不需要进行字符串转换。但是,如果你想要调用CreateWindowEx函数并将Unicode字符串传递给它,你就必须明确分配缓存,并调用函数,以便执行从Unicode到ANSI字符串的转换操作。然后你可以调用CreateWindowEx,传递ANSI字符串。当CreateWindowEx函数返回时,你就能释放临时缓存。这比使用Windows 2000上的Unicode要麻烦得多。在本章的后面部分中,我要介绍如何在Windows 98下进行这些转换。 虽然Unicode函数的大多数代码在Windows 98中不起任何作用,但是有少数Unicode函数确实拥有非常有用的实现代码。这些函数是: 见原书的P21 可惜的是,这些函数中有许多函数在Windows 98中会出现各种各样的错误。有些函数无法使用某些字体,有些函数会破坏内存堆栈,有些函数会使打印机驱动程序崩溃,如此等等。如果你要使用这些函数,你必须对它们进行大量的测试。即使这样,你可能仍然无法解决问题。因此你必须向用户说明这些情况。 2. 5 Windows CE与Unicode Windows CE操作系统是为小型设备开发的,这些设备的内存很小,并且不带磁盘存储器。你可能认为,由于Microsoft公司的主要目标是建立一种尽可能小的操作系统,因此它会使用ANSI作为自己的字符集。但是Microsoft公司并不是鼠目寸光。他们懂得,采用Windows CE的设备要在世界各地销售,他们希望降低软件开发成本,这样就能更加容易地开发应用程序。为此,Windows CE本身就是使用Unicode的一种操作系统。 但是,为了使Windows CE尽量做得小一些,Microsoft公司决定完全不支持ANSI Windows函数。因此,如果你要为Windows CE开发应用程序,你必须懂得Unicode,并且在整个应用程序中使用Unicode。 2. 6 需要注意的问题 下面让我们进一步明确一下“Microsoft公司对Unicode支持的情况”: * Windows 2000既支持Unicode,也支持ANSI,因此你可以为它们当中的任何一种开发应用程序 * Windows 98 只支持ANSI,你只能为ANSI开发应用程序 * Windows CE只支持Unicode,你只能为Unicode开发应用程序 虽然Microsoft公司试图让软件开发人员能够非常容易地开发在这3种平台上运行是软件,但是Unicode与ANSI之间的差异使得事情变得困难起来,并且这种差异通常是我遇到的最大的问题之一。请不要误解,Microsoft公司坚定地支持Unicode,并且我也坚决鼓励你使用它。不过你应该懂得,你可能遇到一些问题,需要一定的时间来解决这些问题。我建议你尽可能使用Unicode。如果你运行Windows 98,那么只有在必要时才要转换到ANSI。 不过,还有另一个小问题你应该了解,那就是COM。 2.7 对COM的简单说明 当Microsoft公司将COM从16位Windows转换成Win32时,公司作出了一个决定,即,需要字符串的所有COM接口方法都只能接受Unicode字符串。这是个了不起的决定,因为COM通常用于使不同的组件能够互相之间进行通信,而Unicode则是传递字符串的最佳手段。 如果你为Windows 2000或Windows CE开发应用程序,并且也使用COM,那么你将会如虎添翼。在你的整个源代码中使用Unicode,将使与操作系统进行通信和与COM对象进行通信的操作变成一件轻而易举的事情。 如果你为Windows 98开发应用程序,并且也使用COM,那么你将会遇到一些问题。COM要求你使用Unicode字符串。操作系统的大多数函数要求你使用ANSI字符串。那是多么难办的事情啊!我曾经从事过若干个项目的开发,在这些项目中,我编写了许多代码,仅仅是为了来回进行字符串的转换。 2. 8 如何编写Unicode源代码 Microsoft公司为Unicode设计了Windows API,这样,它可以尽量减少对你的代码的影响。实际上,你可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。你只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。 2. 8.1 C运行期库对Unicode的支持 为了利用Unicode字符串,因此定义了一些数据类型。标准的C头文件String.h已经作了修改,以便定义一个字为wchar_t的数据类型,它是一个Unicode字符的数据类型: 见原书P23的程序(1) 例如,如果你想要创建一个缓存,用于存放最多为99个字符的Unicode字符串和一个结尾为零的字符,你可以使用下面这个语句: 见原书P23的程序(2) 该语句创建了一个由100个16位值组成的数组。当然,标准的C运行期字符串函数,如strcpy、strchr和strcat等,只能对ANSI字符串进行操作,它们不能正确地处理Unicode字符串。因此,ANSI C也拥有一组补充函数。图2-1显示了一些标准的ANSI C字符串函数,后面是它们的等价Unicode函数。 图2-1 标准的ANSI C字符串函数和它们的等价Unicode函数 见原书P23的程序(3)和P24的程序 请注意,所有的Unicode函数均以wcs开头,wcs是宽字符串的英文缩写。若要调用Unicode函数,只需用前缀wcs来取代任何ANSI字符串函数的前缀str即可。 说明 大多数软件开发人员可能已经不记得这样一个非常重要的问题了,那就 是Microsoft公司提供的C运行期库与ANSI的标准C运行期库是一致的。 ANSI C规定,C运行期库支持Unicode字符和字符串。这意味着你始终都可 以调用C运行期函数,以便对Unicode字符和字符串进行操作,即使你是在 Windows 98上运行,也可以调用这些函数。换句话说,wcscat,wcslen和wcstok 等函数都能够在Windows 98上很好地运行,这些都是你必须关心的操作系统函数。 对于包含了对str函数或wcs函数进行显式调用的代码来说,你无法非常容易地同时为ANSI和Unicode对这些代码进行编译。在本章前面部分的内容中,我说过可以创建同时为ANSI和Unicode进行编译的单个源代码文件。若要建立这种双重功能,你必须包含Tchar.h文件,而不是包含String.h文件。 Tchar.h文件的唯一作用是帮助你创建ANSI/Unicode通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用str函数或者wcs函数。如果你在编译源代码文件时定义了_UNICODE,这些宏就会引用wcs这组函数。如果你没有定义_UNICODE,那么这些宏将引用str这组宏。 例如,在Tchar.h中有一个宏称为_tcscpy。如果在你包含该头文件时没有定义_UNICODE,那么_tcscpy就会扩展为ANSI的strcpy函数。但是如果定义了_UNICODE,_tcscpy将扩展为Unicode的wcscpy函数。拥有字符串参数的所有C运行期函数都在Tchar.h文件中定义了一个通用宏。如果你使用通用宏,而不是ANSI/Unicode的特定函数,你就能够顺利地创建可以为ANSI或Unicode进行编译的源代码。 但是,除了使用这些宏之外,还有一些操作你是必须进行的。Tchar.h文件包含了一些其他的宏。 若要定义一个ANSI/Unicode通用的字符串数组,请使用下面的TCHAR数据类型。如果定义了_UNICODE,TCHAR将声明为下面的形式: 见原书P25的程序(1) 如果没有定义_UNICODE,则TCHAR将声明为下面的形式: 见原书P25的程序(2) 使用该数据类型,你可以象下面这样分配一个字符串: 见原书P25的程序(3) 你也可以创建对字符串的指针: 见原书P25的程序(4) 不过上面这行代码存在一个问题。按照默认设置,Microsoft公司的C++编译器能够编译所有的字符串,就象它们是ANSI字符串,而不是Unicode字符串。因此,如果没有定义_UNICODE,该编译器将能正确地编译这一行代码。但是,如果定义了_UNICODE,就会产生一个错误。若要生成一个Unicode字符串而不是ANSI字符串,你必须将该代码行改写为下面的样子: 见原书P25的程序(5) 原义字符串前面的大写字母L,用于告诉编译器该字符串应该作为Unicode字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_UNICODE时,程序才能成功地进行编译。我们需要另一个宏,以便有选择地在原义字符串的前面加上大写字母L。这项工作由_TEXT宏来完成,_TEXT宏也在Tchar.h文件中做了定义。如果定义了_UNICODE,那么_TEXT定义为下面的形式: 见原书P25的程序(6)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧