《汇编语言 基于x86处理器》第十一章 MS-DOS 编程部分的代码 part 1

▶ 书中第十一章的程序,主要讲了 Windows 接口,在小黑框中进行程序交互

● 代码,四种消息框

 1 INCLUDE Irvine32.inc
 2 
 3 .data
 4 captionW    BYTE "Warning", 0                           ; 标题
 5 warningMsg  BYTE "皮一下很开心", 0                       ; 消息框内容,支持 Unicode
 6 
 7 captionQ    BYTE "Question", 0 
 8 questionMsg BYTE "皮一下很开心?", 0    
 9 
10 captionC    BYTE "Information", 0
11 infoMsg     BYTE "那皮一下?", 0dh, 0ah, "不皮也行", 0
12 
13 captionH    BYTE "Halt", 0
14 haltMsg     BYTE "没皮成,被打了", 0
15 
16 .code
17 main PROC
18     INVOKE MessageBox, NULL, ADDR warningMsg, ADDR captionW, MB_OK + MB_ICONEXCLAMATION                         ; 警告图标,OK 按钮
19 
20     INVOKE MessageBox, NULL, ADDR questionMsg, ADDR captionQ, MB_YESNO + MB_ICONQUESTION                        ; 问号图标,Yes / No 按钮            
21     cmp eax, IDYES                                                                                              ; 返回值在 eax 中
22 
23     INVOKE MessageBox, NULL, ADDR infoMsg, ADDR captionC, MB_YESNOCANCEL + MB_ICONINFORMATION + MB_DEFBUTTON2   ; i 图标,Yes / No / Cancel 按钮
24 
25     INVOKE MessageBox, NULL, ADDR haltMsg, ADDR captionH, MB_OK + MB_ICONSTOP                                   ; 叉叉图标, OK 按钮
26 
27     call WaitMsg
28     exit
29 main ENDP
30 END main

● 创建 Windows 窗口和相关程序窗口

  1 INCLUDE Irvine32.inc
  2 INCLUDE GraphWin.inc
  3 
  4 .data
  5 AppLoadMsgTitle BYTE "Application Loaded",0
  6 AppLoadMsgText  BYTE "WM_CREATE message received.",0
  7 
  8 PopupTitle      BYTE "Popup Window",0
  9 PopupText       BYTE "WM_LBUTTONDOWN message received.",0
 10 
 11 GreetTitle      BYTE "Main Window",0
 12 GreetText       BYTE "CreateWindow and UpdateWindow are called.",0
 13 
 14 CloseMsg        BYTE "WM_CLOSE message received",0
 15 
 16 ErrorTitle      BYTE "Error",0
 17 WindowName      BYTE "ASM Windows App",0
 18 className       BYTE "ASMWin",0
 19 
 20 MainWin WNDCLASS <NULL,WinProc,NULL,NULL,NULL,NULL,NULL, COLOR_WINDOW,NULL,className> ; 声明应用的窗口结构
 21 
 22 msg         MSGStruct <>
 23 winRect     RECT <>
 24 hMainWnd    DWORD ?
 25 hInstance   DWORD ?
 26 
 27 .code
 28 WinMain PROC
 29     INVOKE GetModuleHandle, NULL
 30     mov hInstance, eax
 31     mov MainWin.hInstance, eax
 32 
 33     INVOKE LoadIcon, NULL, IDI_APPLICATION  ; 读取图标
 34     mov MainWin.hIcon, eax
 35     INVOKE LoadCursor, NULL, IDC_ARROW      ; 读取光标
 36     mov MainWin.hCursor, eax
 37 
 38     INVOKE RegisterClass, ADDR MainWin      ; 挂载程序
 39     .IF eax == 0
 40         call ErrorHandler                   ; 错误退出
 41         jmp Exit_Program
 42     .ENDIF
 43 
 44     INVOKE CreateWindowEx, 0, ADDR className, ADDR WindowName,         ; 获取主窗口句柄
 45         MAIN_WINDOW_STYLE, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL
 46     mov hMainWnd,eax
 47     .IF eax == 0
 48         call ErrorHandler
 49         jmp  Exit_Program
 50     .ENDIF
 51 
 52     INVOKE ShowWindow, hMainWnd, SW_SHOW        ; 绘制主窗口
 53     INVOKE UpdateWindow, hMainWnd
 54 
 55     INVOKE MessageBox, hMainWnd, ADDR GreetText, ADDR GreetTitle, ; 扫描键盘 PeekInput.asm
 56 INCLUDE Irvine32.inc
 57 INCLUDE Macros.inc
 58 
 59 EVENT_BUFFER_SIZE = 1
 60 
 61 .data
 62 inputKey    BYTE ?
 63 stdInHandle DWORD ?
 64 
 65 .code
 66 main PROC    
 67     INVOKE  GetStdHandle, STD_INPUT_HANDLE
 68     mov     stdInHandle, eax 
 69     INVOKE  FlushConsoleInputBuffer, stdInHandle ; 清空控制台输入缓冲区,控制台程序在程序启动时焦点在缓冲区中
 70 
 71 L1:
 72     mov  eax, 100           ; 等待操作系统时间片(防止程序可以接受外中断以前就已经有键盘输入)
 73     call Delay
 74     call ReadKey_           ; 读取键盘中断
 75     jz   L1                 ; 通过 ZF 判断是否继续循环
 76 
 77 keyPressed:
 78     mWrite "Key code:  "    ; 返回键盘符号和扫描码
 79     mShow  DX,hn
 80     mWrite "Scan code: "
 81     mShow  AH,hn
 82 
 83     call Crlf
 84     call WaitMsg
 85     exit
 86 main ENDP
 87 
 88 ReadKey_ PROC
 89 
 90 NUM_KEYS = 1
 91 CTRL_KEY = 11h
 92 repeatCount TEXTEQU <BYTE PTR [keybuf+4]>               ; 从缓冲区的不同部分取出相应的信息
 93 virtualKeyCode TEXTEQU <WORD PTR [keybuf+10]>
 94 scanCode TEXTEQU <[keybuf+12]>
 95 asciiCode TEXTEQU <[keybuf+14]>
 96 
 97 .data
 98 keybuf BYTE 50 DUP(0)
 99 recordsRead DWORD ?
100 .code
101     INVOKE PeekConsoleInput,                           ; 速去按键
102         stdInHandle, ADDR keybuf, 1, ADDR recordsRead   ; 句柄,缓冲区,按键计数,按键描述
103     cmp recordsRead, 0
104     je  quit                                            ; 无效按键,置 ZF = 1
105     
106     INVOKE FlushConsoleInputBuffer, stdInHandle         ; 清空缓冲区
107     
108     cmp  WORD PTR keybuf, KEY_EVENT                     ; 判断是否有键按下
109     jne  NoKey              
110 
111 Check_Count:
112     cmp  repeatCount, 1     ; 按键重复数
113     jne  NoKey          
114 
115 Get_Codes:
116     mov ah, scanCode        ; 扫描码放入 ah
117     mov al, asciiCode       ; ASCII 码放入 al
118     mov dx, virtualKeyCode  ; 按键名放入 dx
119     or  dx, dx              ; 置 ZF = 0
120     jmp quit
121 
122 NoKey:                      ; 无键按下,置 ZF = 1
123     test eax, 0
124 
125 quit:
126     ret
127 ReadKey_ ENDP
128 
129 END main
130  ; 绘制欢迎界面
131 
132 Message_Loop:    
133     INVOKE GetMessage, ADDR msg, NULL,NULL,NULL    
134     .IF eax == 0                                ; eax 无信息时退出 
135         jmp Exit_Program
136     .ENDIF
137     
138     INVOKE DispatchMessage, ADDR msg            ; 主程序中显示信息
139     jmp Message_Loop                            ; 队列循环等待外中断
140 
141 Exit_Program:
142     call waitMsg
143     INVOKE ExitProcess, 0
144 WinMain ENDP
145 
146 WinProc PROC, hWnd:DWORD, localMsg:DWORD, wParam:DWORD, lParam:DWORD
147     mov eax, localMsg    
148     .IF eax == WM_CREATE                                                ; 创建窗口
149         INVOKE MessageBox, hWnd, ADDR AppLoadMsgText, ADDR AppLoadMsgTitle, MB_OK
150         jmp WinProcExit
151     .ELSEIF eax == WM_LBUTTONDOWN                                       ; 鼠标左键单击
152         INVOKE MessageBox, hWnd, ADDR PopupText, ADDR PopupTitle, MB_OK
153         jmp WinProcExit
154     .ELSEIF eax == WM_CLOSE                                             ; 关闭窗口
155         INVOKE MessageBox, hWnd, ADDR CloseMsg, ADDR WindowName, MB_OK
156         INVOKE PostQuitMessage, 0
157         jmp WinProcExit
158     .ELSE                                                               ; 其他信息
159         INVOKE DefWindowProc, hWnd, localMsg, wParam, lParam
160         jmp WinProcExit
161     .ENDIF
162 
163 WinProcExit:
164     ret
165 WinProc ENDP
166 
167 ErrorHandler PROC
168 .data
169 pErrorMsg  DWORD ?          ; 错误信息字符串
170 messageID  DWORD ?
171 .code
172     INVOKE GetLastError     ; 获取错误信息 ID
173     mov messageID,eax
174 
175     INVOKE FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_FROM_SYSTEM,     ; 获取错误信息字符串
176         NULL, messageID, NULL, ADDR pErrorMsg, NULL, NULL
177     
178     INVOKE MessageBox, NULL, pErrorMsg, ADDR ErrorTitle, MB_ICONERROR + MB_OK               ; 显示错误信息
179     
180     INVOKE LocalFree, pErrorMsg                                                             ; 释放堆变量
181     ret
182 ErrorHandler ENDP
183 
184 END WinMain

● 使用 ReadConsole 从终端输入

 1 INCLUDE Irvine32.inc
 2 
 3 BufSize = 80
 4 
 5 .data
 6 buffer BYTE BufSize DUP(?)
 7 stdInHandle HANDLE ?
 8 bytesRead   DWORD ?
 9 
10 .code
11 main PROC
12     INVOKE GetStdHandle, STD_INPUT_HANDLE
13     mov    stdInHandle, eax                 ; 注意保存返回的句柄    
14     INVOKE ReadConsole, stdInHandle, ADDR buffer, BufSize, ADDR bytesRead, 0    ; 参数分别为:句柄,存储内存地址,最大字符数,未使用 
15 
16     mov    esi, OFFSET buffer               ; 显示保存的字符串
17     mov    ecx, bytesRead
18     mov    ebx, TYPE buffer
19     call    DumpMem                         ; 注意结尾有 0Dh, 0Ah,即为 "
", 0
20 
21     call WaitMsg
22     exit
23 main ENDP
24 END main

● 使用WriteConsole 输出到终端,参数与输入差不多

 1 INCLUDE Irvine32.inc
 2 
 3 .data
 4 endl EQU <0dh,0ah> ; 换行符
 5 
 6 message LABEL BYTE BYTE "Some words", endl
 7 messageSize DWORD ($-message)
 8 
 9 consoleHandle HANDLE 0
10 bytesWritten  DWORD ?
11 
12 .code
13 main PROC
14     INVOKE GetStdHandle, STD_OUTPUT_HANDLE
15     mov consoleHandle,eax
16   
17     INVOKE WriteConsole, consoleHandle, ADDR message, messageSize, ADDR bytesWritten, 0
18 
19     call waitmsg
20     INVOKE ExitProcess, 0
21 main ENDP
22 END main

● 终端的各种操作

 1 INCLUDE Irvine32.inc
 2 
 3 .data
 4 titleStr    BYTE "This is title", 0
 5 message     BYTE ": Something to write on screen buffer", 0dh, 0ah
 6 messageSize DWORD ($-message)
 7 cursorInfo CONSOLE_CURSOR_INFO <>
 8 scrSize COORD <120,60>
 9 xyPos COORD <20,5>
10 consoleInfo CONSOLE_SCREEN_BUFFER_INFO <>
11 
12 outHandle       HANDLE 0
13 bytesWritten    DWORD ?               
14 lineNum         DWORD 0
15 windowRect      SMALL_RECT <0,0,60,11>  ; 显示窗口在输出缓冲区中的坐标,分别为左、上、右、下,单位是字符
16 
17 .code
18 main PROC
19     INVOKE GetStdHandle, STD_OUTPUT_HANDLE
20     mov outHandle, eax
21 
22     INVOKE SetConsoleTitle, ADDR titleStr                   ; 标题
23 
24     INVOKE GetConsoleCursorInfo, outHandle, ADDR cursorInfo ; 获取光标信息
25     mov cursorInfo.dwSize, 75                               ; 光标缩放为 75%
26     INVOKE SetConsoleCursorInfo, outHandle, ADDR cursorInfo
27 
28     INVOKE SetConsoleScreenBufferSize, outHandle,scrSize    ; 设置缓冲区尺寸
29 
30     INVOKE SetConsoleCursorPosition, outHandle, xyPos       ; 设置光标位置
31     
32     INVOKE GetConsoleScreenBufferInfo, outHandle, ADDR consoleInfo  ; 获取缓冲区和输出窗口信息
33 
34 .REPEAT
35     mov    eax, lineNum                 ; 打印行号
36     call    WriteDec            
37     INVOKE WriteConsole, outHandle, ADDR message, messageSize, ADDR bytesWritten, 0 ; 随便写点什么
38     inc  lineNum
39 .UNTIL lineNum > 50
40 
41     INVOKE SetConsoleWindowInfo, outHandle, TRUE, ADDR windowRect   ; 调整缓冲区窗口位置
42     
43     call Readchar        ; 等待键盘输入不能用 WaitMsg,否则显示窗口强制重定位到最后
44     call Clrscr          ; 清屏
45     call Waitmsg
46     INVOKE ExitProcess, 0
47 main ENDP
48 END main

● 键盘单键测试

 1 INCLUDE Irvine32.inc
 2 INCLUDE Macros.inc
 3 
 4 .code
 5 main PROC    
 6     INVOKE GetKeyState, VK_NUMLOCK      ; 检测数字键盘锁定状态
 7     call DumpRegs
 8     test al, 1
 9     .IF !Zero?
10         mWrite <"NumLock ON",0dh,0ah>
11     .ELSE
12         mWrite <"NumLock OFF",0dh,0ah>
13     .ENDIF
14 
15     INVOKE GetKeyState, VK_LSHIFT       ; 检测左 Shift 锁定状态
16     call DumpRegs  
17     test eax, 80000000h
18     .IF !Zero?
19         mWrite <"L-Shift DOWN",0dh,0ah>
20     .ELSE
21         mWrite <"L-Shift UP",0dh,0ah>
22     .ENDIF
23 
24     call WaitMsg
25     exit
26 main ENDP
27 END main

● 返回键盘扫描码和按键

 1 INCLUDE Irvine32.inc
 2 INCLUDE Macros.inc
 3 
 4 EVENT_BUFFER_SIZE = 1
 5 
 6 .data
 7 inputKey    BYTE ?
 8 stdInHandle DWORD ?
 9 
10 .code
11 main PROC    
12     INVOKE  GetStdHandle, STD_INPUT_HANDLE
13     mov     stdInHandle, eax 
14     INVOKE  FlushConsoleInputBuffer, stdInHandle ; 清空控制台输入缓冲区,控制台程序在程序启动时焦点在缓冲区中
15 
16 L1:
17     mov  eax, 100           ; 等待操作系统时间片(防止程序可以接受外中断以前就已经有键盘输入)
18     call Delay
19     call ReadKey_           ; 读取键盘中断
20     jz   L1                 ; 通过 ZF 判断是否继续循环
21 
22 keyPressed:
23     mWrite "Key code:  "    ; 返回键盘符号和扫描码
24     mShow  DX,hn
25     mWrite "Scan code: "
26     mShow  AH,hn
27 
28     call Crlf
29     call WaitMsg
30     exit
31 main ENDP
32 
33 ReadKey_ PROC
34 
35 NUM_KEYS = 1
36 CTRL_KEY = 11h
37 repeatCount TEXTEQU <BYTE PTR [keybuf+4]>               ; 从缓冲区的不同部分取出相应的信息
38 virtualKeyCode TEXTEQU <WORD PTR [keybuf+10]>
39 scanCode TEXTEQU <[keybuf+12]>
40 asciiCode TEXTEQU <[keybuf+14]>
41 
42 .data
43 keybuf BYTE 50 DUP(0)
44 recordsRead DWORD ?
45 .code
46     INVOKE PeekConsoleInput,                           ; 速去按键
47         stdInHandle, ADDR keybuf, 1, ADDR recordsRead   ; 句柄,缓冲区,按键计数,按键描述
48     cmp recordsRead, 0
49     je  quit                                            ; 无效按键,置 ZF = 1
50     
51     INVOKE FlushConsoleInputBuffer, stdInHandle         ; 清空缓冲区
52     
53     cmp  WORD PTR keybuf, KEY_EVENT                     ; 判断是否有键按下
54     jne  NoKey              
55 
56 Check_Count:
57     cmp  repeatCount, 1     ; 按键重复数
58     jne  NoKey          
59 
60 Get_Codes:
61     mov ah, scanCode        ; 扫描码放入 ah
62     mov al, asciiCode       ; ASCII 码放入 al
63     mov dx, virtualKeyCode  ; 按键名放入 dx
64     or  dx, dx              ; 置 ZF = 0
65     jmp quit
66 
67 NoKey:                      ; 无键按下,置 ZF = 1
68     test eax, 0
69 
70 quit:
71     ret
72 ReadKey_ ENDP
73 
74 END main

● 简单的计时器

 1 ; TimingLoop.asm
 2 
 3 INCLUDE Irvine32.inc
 4 
 5 TIME_LIMIT = 5000
 6 
 7 .data
 8 startTime DWORD ?
 9 dot BYTE ".",0
10 
11 .code
12 main PROC
13     INVOKE GetTickCount     ; 给一个开始时间
14     mov startTime, eax
15 
16 L1:
17     mov  edx, OFFSET dot    ; 打印一个点
18     call WriteString
19 
20     INVOKE Sleep, 100       ; 等待 100 ms 
21 
22     INVOKE GetTickCount     ; 计算经历的时间
23     sub  eax, startTime     
24     cmp  eax, TIME_LIMIT
25     jb   L1
26 
27 L2:    
28     call waitMsg
29     exit
30 main ENDP
31 END main
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9696576.html