汇编语言MS-Windows编程简述

一个 Windows 应用程序开始的时候,要么创建一个控制台窗口,要么创建一个图形化窗口。本教程的项目文件一直把如下选项与 LINK 命令一起使用。它告诉链接器创建一个基于控制台的应用程序:

/SUBSYSTEM:CONSOLE

控制台程序的外观和操作就像 MS-DOS 窗口,它的一些改进部分将在后面进行介绍。控制台有一个输入缓冲区以及一个或多个屏幕缓冲区:

1) 输入缓冲区(input buffer):

包含一组输入记录(input records),其中的每个记录都是一个输入事件的数据。输入事件的例子包括键盘输入、鼠标点击,以及用户调整控制台窗口大小。

2) 屏幕缓冲区(screen buffer):

是字符与颜色数据的二维数组,它会影响控制台窗口文本的外观。

Win32 API 参考信息

函数

在接下来的讲解中将介绍 Win32 API 函数的子集并给岀一些简单的例子。由于篇幅的限制,将不会涉及很多细节。如果想了解更多信息,请访问 Microsoft MSDN 网站(地址为:www.msdn.microsoft.com)。在搜索函数或标识符时,把 Filtered by 参数设置为 Platform SDK。

常数

阅读 Win32 API 函数的文档时,常常会见到常量名,如 TIME_ZONE_ID_UNKNOWN。少数情况下,这些常量已经在 SmallWin.inc 中定义过。例如,头文件 WinNT.h 就定义了 TIME_ZONE_ID_UNKNOWN 及相关常量:

#define TIME_ZONE_ID_UNKNOWN 0
#define TIME_ZONE_ID_STANDARD 1
#define TIME_ZONE_ID_DAYLIGHT 2

利用这个信息,可以将下述语句添加到 SmallWin.h 或者用户自己的头文件中:

TIME_ZONE_ID_UNKNOWN = 0
TIME_ZONE_ID_STANDARD = 1
TIME_ZONE_ID_DAYLIGHT = 2

字符集和 Windows API 函数

调用 Win32 API 函数时会使用两类字符集:8 位的 ASCII/ANSI 字符集和 16 位的 Unicode 字符集(所有近期的 Windows 版本中都有)。

Win32 函数可以处理的文本通常有两种版本:一种以字母 A 结尾(8 位 ANSI 字符),另一种以 W 结尾(宽字符集,包括了 Unicode)。WriteConsole 即为其中之一:

WriteConsoleA
WriteConsoleW

Windows95 和 98 不支持以 W 结尾的函数名。另一方面,在所有近期的 Windows 版本中,Unicode 都是原生字符集。例如调用名为 WriteConsoleA 的函数,则操作系统将把字符从 ANSI 转换为 Unicode,再调用 WriteConsoleW。

在 Microsoft MSDN 链接库的函数文件中,如 WriteConsole,尾字符 A 和 W 都被省略了。

WriteConsole EQU <WriteConsoleA>

这个定义使得程序能按 WriteConsole 的通用名对其进行调用。

高级别和低级别访问

控制台访问有两个级别,这就能够在简单控制和完全控制之间进行权衡:
  • 高级别控制台函数从控制台输入缓冲区读取字符流,并将字符数据写入控制台的屏幕缓冲区。输入和输出都可以重定向到文本文件。
  • 低级别控制台函数检索键盘和鼠标事件,以及用户与控制台窗口交互 ( 拖曳、调整大小等 ) 的详细信息。这些函数还允许对窗口大小、位置以及文本颜色进行详细控制。

Windows 数据类型

Win32 函数使用 C/C++ 程序员的函数声明进行记录。在这些声明中,所有函数参数类型要么基于标准 C 类型,要么基于 MS-Windows 预定义类型 (下表中列出了部分类型 ) 之一。

MS-Windows 类型 MASM类型 说明
BOOL, BOOLEAN  DWORD 布尔值 (TRUE 或 FALSE)
BYTE BYTE 8 位无符号整数
CHAR BYTE 8 位 Windows ANSI 字符
COLORREF DWORD   作为颜色值的 32 位数值
DWORD DWORD 32 位无符号整数
HANDLE DWORD 对象句柄
HFILE  DWORD   用 OpenFile 打开的文件的句柄
INT  SDWORD 32 位有符号整数
LONG SDWORD 32 位有符号整数
LPARAM DWORD 消息参数,由窗口过程和回调函数使用
LPCSTR PTR BYTE 32 位指针,指向由 8 位 Windows (ANSI)字符组成的空字节结束的字符串常量
LPCVOID DWORD 指向任何类型的常量
LPSTR PTR BYTE 32 位指针,指向由 8 位 Windows (ANSI) 字符组成的空字节结束的字符串
LPCTSTR PTR WORD 32 位指针,指向对 Unicode 和双字节字符集可移植的字符串常量
LPTSTR  PTR WORD 32 位指针,指向对 Unicode 和双字节字符集可移植的字符串
LPVOID DWORD 32 位指针,指向未指定类
LRESULT DWORD 窗口过程和回调函数返回的 32 位数值
SIZE_T DWORD  一个指针可以指向的最大字节数
UNIT DWORD 32 位无符号整数
WNDPROC DWORD 32 位指针,指向窗口过程
WORD WORD 16 位无符号整数
WPARAM DWORD 作为参数传递给窗口过程或回调函数的 32 位数值

区分数据值和指向值的指针是很重要的。以字母 LP 开头的类型名是长指针 (long pointer),指向其他对象。

SmallWin.inc 头文件

SmallWin.inc 是一个头文件,其中包含了 Win32 API 编程的常量定义、等价文本以及函数原型。通过本教程一直使用的 Irvine32.inc,SmallWin.inc 被自动包含在程序中。

大多数常量都可以在用于 C 和 C++ 编程的头文件 Windows.h 中找到。与它的名字不同,SmallWin.inc 文件相当大, 因此这里只展示其突出部分:

DO_NOT_SHARE = 0
NULL = 0
TRUE = 1
FALSE = 0
;Win32 控制台句柄
STD_INPUT_HANDLE EQU -10
STD_OUTPUT_HANDLE EQU -11
STD_ERROR_HANDLE EQU -12

类型 HANDLE 是 DWORD 的代名词,能帮助函数原型与 Microsoft Win32 文档更加一致:

HANDLE TEXTEQU <DWORD>

SmallWin.inc 也包括用于 Win32 调用的结构定义。下面给出了两个结构定义:

COORD STRUCT
    X WORD ?
    Y WORD ?
COORD ENDS

SYSTEMTIME STRUCT
    wYear WORD ?
    wMonth WORD ?
    wDayOfWeek WORD ?
    wDay WORD ?
    wHour WORD ?
    wMinute WORD ?
    wSecond WORD ?
    wMilliseconds WORD ?
SYSTEMTIME ENDS

控制台句柄

几乎所有的 Win32 控制台函数都要求向其传递一个句柄作为第一个实参。句柄 (handle) 是 一个 32 位无符号整数,用于唯一标识一个对象,例如一个位图、画笔或任何输入/输岀设备:

STD_INPUT_HANDLE standard input
STD_OUTPUT_HANDLE standard output
STD_ERROR_HANDLE standard error output

上述句柄中的后两个用于写控制台活跃屏幕缓冲区。

GetStdHandle 函数返回一个控制台流的句柄:输入、输出或错误输出。基于控制台的程序中所有的输入/输出操作都需要句柄。函数原型如下:

GetStdHandle PROTO,
    nStdHandle:HANDLE        ;句柄类型

nStdHandle 可以是 STD_INPUT_HANDLE、STD_OUTPUT_HANDLE 或者 STD_ERROR_ HANDLE。函数用 EAX 返回句柄,且应将它复制给变量保存。下面是一个调用示例:

.data
inputHandle HANDLE ?
.code
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov inputHandle;eax