• 《汇编语言 基于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
  • 相关阅读:
    MySQL令人咋舌的隐式转换
    MySQL 数据库基础(二)(MySQL 服务基础与使用 MySQL 数据库)
    以友盟+U-Push为例,深度解读消息推送的筛选架构解决方案应用与实践
    逆向工程,调试Hello World !程序(更新中)
    520了,用32做个简单的小程序
    postgresql 数据库 update更新慢的原因(已解决)
    面试题单例模式的五种写法(枚举妙用)
    人工智能能力提升指导总结
    数据结构-队列(2)-循环队列
    数据结构-队列(1)
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9696576.html
Copyright © 2020-2023  润新知