汇编语言控制台窗口操作

Win32 API 提供了对控制台窗口及其缓冲区相当大的控制权。下图显示了屏幕缓冲区可以大于控制台窗口当前显示的行数。控制台窗口就像是一个“视窗”,显示部分缓冲区。

屏幕缓冲区和控制台窗口

下列函数影响的是控制台窗口及其相对于屏幕缓冲区的位置:
  • SetConsoleWindowInfo:设置控制台窗口相对于屏幕缓冲区的大小和位置。
  • GetConsoleScreenBufferInfo:返回(还包括其他一些信息)控制台窗口相对于屏幕缓冲区的矩形坐标。
  • SetConsoleCursorPosition:将光标设置在屏幕缓冲区内的任何位置;如果区域不可见,则移动控制台窗口直到光标可见。
  • ScrollConsoleScreenBuffer:移动屏幕缓冲区中的一些或全部文本,本函数会影响控制台窗口显示的文本。

1) SetConsoleTitle

函数 SetConsoleTitle 可以改变控制台窗口的标题。示例如下:

.data
.titleStr BYTE "Console title", 0
.code
INVOKE SetConsoleTitle, ADDR titleStr

2) GetConsoleScreenBufferInfo

函数 GetConsoleScreenBufferInfo 返回控制台窗口的当前状态信息。它有两个参数:控制台屏幕的句柄和指向该函数填充的结构的指针:

GetConsoleScreenBufferInfo PROTO,
    hConsoleOutput:HANDLE,
    lpConsoleScreenBufferInfo:PTR CONSOLE_SCREEN_BUFFER_INFO

CONSOLE_SCREEN_BUFFER_INFO 结构如下:
  1. CONSOLE_SCREEN_BUFFER_INFO STRUCT
  2. dwSize COORD <>
  3. dwCursorPosition COORD <>
  4. wAttributes WORD ?
  5. srWindow SMALL_RECT <>
  6. dwMaximumWindowSize COORD <>
  7. CONSOLE_SCREEN_BUFFER_INFO ENDS
dwSize 按字符行列数返回屏幕缓冲区大小。dwCursorPosition 返回光标的位置。这两个字段都是 COORD 结构。

wAttributes 返回字符的前景色和背景色,字符由诸如 WriteConsole 和 WriteFile 等函数写到控制台。srWindow 返回控制台窗口相对于屏幕缓冲区的坐标。

dwMaximumWindowSize 以当前屏幕缓冲区的大小、字体和视频显示大小为基础,返回控制台窗口的最大尺寸。函数示例调用如下所示:

.data
consoleInfo CONSOLE_SCREEN_BUFFER_INFO <>
outHandle HANDLE ?
.code
INVOKE GetConsoleScreenBufferInfo, outHandle,
    ADDR consoleInfo

3) SetConsoleWindowInfo 函数

函数 SetConsoleWindowInfo 可以设置控制台窗口相对于其屏幕缓冲区的大小和位置。函数原型如下:

SetConsoleWindowInfo PROTO,
    hConsoleOutput:HANDLE,                  ;屏幕缓冲区句柄
    bAbsolute:DWORD,                             ;坐标类型
    lpConsoleWindow:PTR SMALL_RECT  ;矩形窗口指针

bAbsolute 说明如何使用结构中由 lpConsoleWindow 指出的坐标。如果 bAbsolute 为真,则坐标定义控制台窗口新的左上角和右下角。如果 bAbsolute 为假,则坐标与当前窗口坐标相加。

下面的程序向屏幕缓冲区写 50 行文本。然后重定义控制台窗口的大小和位置,有效地向后滚动文本。该程序使用了函数 SetConsoleWindowInfo:
  1. ; 滚动控制台窗口 (Scroll.asm)
  2.  
  3. INCLUDE Irvine32.inc
  4.  
  5. .data
  6. message BYTE ": This line of text was written "
  7. BYTE "to the screen buffer",0dh,0ah
  8. messageSize DWORD ($-message)
  9.  
  10. outHandle HANDLE 0 ; 标准输出句柄
  11. bytesWritten DWORD ? ; 已写入字节数
  12. lineNum DWORD 0
  13. windowRect SMALL_RECT <0,0,60,11> ; 上,下,左,右
  14.  
  15. .code
  16. main PROC
  17. INVOKE GetStdHandle, STD_OUTPUT_HANDLE
  18. mov outHandle,eax
  19.  
  20. .REPEAT
  21. mov eax,lineNum
  22. call WriteDec ; 显示每行编号
  23. INVOKE WriteConsole,
  24. outHandle, ; 控制台输出句柄
  25. ADDR message, ; 字符串指针
  26. messageSize, ; 字符串长度
  27. ADDR bytesWritten, ; 返回已写字节数
  28. 0 ; 未使用
  29. inc lineNum ; 下一行编号
  30. .UNTIL lineNum > 50
  31.  
  32. ; 调整控制台窗口相对于屏幕缓冲区的大小和位置
  33. INVOKE SetConsoleWindowInfo,
  34. outHandle,
  35. TRUE,
  36. ADDR windowRect
  37.  
  38. call Readchar ; 等待按键
  39. call Clrscr ; 清除屏幕缓冲区
  40. call Readchar ; 等待第二次按键
  41.  
  42. INVOKE ExitProcess,0
  43. main ENDP
  44. END main
最好能直接从 MS-Windows Exlporer 中,或者直接以命令行形式运行程序,而不使用集成的编辑环境。否则,编辑器可能会影响控制台窗口的行为和外观。在程序结束时需要两次按键:第一次清除屏幕缓冲区,第二次结束程序。

4) SetConsoleScreenBufferSize 函数

函数 SetConsoleScreenBufferSize 可以将屏幕缓冲区设置为 X 列 * Y 行。其原型如下:

SetConsoleScreenBufferSize PROTO,
    hConsoleOutput:HANDLE,                 ;屏幕缓冲区句柄
    dwSize:COORD                                   ;新屏幕缓冲区大小