; #########################################################################

      .386
      .model flat, stdcall
      option casemap :none   ; case sensitive

; #########################################################################

    
      include \masm32\include\windows.inc
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc
      include \masm32\include\gdi32.inc
      include \masm32\include\masm32.inc
      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
      includelib \masm32\lib\gdi32.lib
      includelib \masm32\lib\masm32.lib
;      include macro.asm

; #########################################################################
      szText MACRO Name, Text:VARARG
        LOCAL lbl
          jmp lbl
            Name db Text,0
          lbl:
        ENDM
      m2m MACRO M1, M2
        push M2
        pop  M1
      ENDM
      return MACRO arg
        mov eax, arg
        ret
      ENDM
       CTXT MACRO quoted_text:VARARG
       comment *
       这些宏定义在这里没什么实际意义,但是如果把这些写好放在一个文件里,这样如果经常使用直接
       包含这个文件就方便了很多,O(∩_∩)O哈哈~,书上看到的,虽然对我这个小程序不实用,但是好习惯要学习。  
       *
        EXITM <offset literal(quoted_text)>        
      ENDM
      literal MACRO quoted_text:VARARG
        LOCAL local_text
        .data
          local_text db quoted_text,0
        .code
        EXITM <local_text>
      ENDM

   
    RadioID01        equ     2001
    RadioID02        equ     2002
    RadioID03        equ     2003
    RadioID04        equ     2004
    RadioID05        equ     2005
    RadioID06        equ     2006
    EditID01         equ     700
    EditID02         equ     701
    ButtonID         equ     500
    ID_Timer         equ     1
   
        WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
        WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
        TopXY PROTO   :DWORD,:DWORD
        Paint_Proc PROTO :DWORD,:DWORD 
        NcPaint_Proc PROTO :DWORD,:DWORD
        FrameCtrl PROTO :DWORD,:DWORD,:DWORD,:DWORD
        FrameWindow PROTO :DWORD,:DWORD,:DWORD,:DWORD
        EditSl PROTO  :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
        Static PROTO  :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
        PushButton PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
        DecToBin PROTO
        BinToDec PROTO
        DecToOct PROTO
        OctToDec PROTO
        DecToHex PROTO
        HexToDec PROTO
       
    .data
        szDisplayName  db           "Number System Converter(Binary Octal Decimal Hexadecimal)",0 
        szText1        db           "请输入正确的二进制数(0、1)",0
        szCaption1     db           "二进制与十进制间的转换",0
        szText2        db           "请输入正确的八进制数(0-8)",0
        szCaption2     db           "八进制与十进制间的转换",0
        szText3        db           "请输入正确的十六进制数(0-9,a-f或A-F)",0
        szCaption3     db           "十六进制与十进制间的转换",0
        CommandLine   dd 0
        hWnd          dd 0
        hInstance     dd 0
        hEdit1        dd 0
        hEdit2        dd 0
        hButn1        dd 0
        hFont         dd 0                 ;字体
        szChange01 db    "十进制到二进制",0
        szChange02 db    "二进制到十进制",0
        szChange03 db    "十进制到八进制",0
        szChange04 db    "八进制到十进制",0
        szChange05 db    "十进制到十六进制",0
        szChange06 db    "十六进制到十进制",0
        szFmtDecToHex db '%x',0
        szFmtHexToDec db '%u',0
       
     
    .DATA?
    hRadio01        dd     ?
    hRadio02        dd     ?
    hRadio03        dd     ?
    hRadio04        dd     ?
       
    szBuf           db 128 dup(?)
    dwLen           dd ?                ;标题长度    字节数
    dwNum           dd ?                ;走过的长度  字节数

    .code

start:
        invoke GetModuleHandle,NULL
        mov hInstance, eax
        invoke GetCommandLine
        mov CommandLine, eax
        invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
        invoke ExitProcess,eax

; #########################################################################

WinMain proc hInst     :DWORD,
             hPrevInst :DWORD,
             CmdLine   :DWORD,
             CmdShow   :DWORD

        LOCAL wc   :WNDCLASSEX
        LOCAL msg  :MSG

        LOCAL Wwd  :DWORD
        LOCAL Wht  :DWORD
        LOCAL Wtx  :DWORD
        LOCAL Wty  :DWORD

        mov wc.cbSize,         sizeof WNDCLASSEX
        mov wc.style,          CS_HREDRAW or CS_VREDRAW \
                               or CS_BYTEALIGNWINDOW
        mov wc.lpfnWndProc,    offset WndProc
        mov wc.cbClsExtra,     NULL
        mov wc.cbWndExtra,     NULL
        m2m wc.hInstance,      hInst                       ;<< NOTE: macro not mnemonic
        mov wc.hbrBackground,  COLOR_WINDOW+9
        mov wc.lpszMenuName,   NULL
        mov wc.lpszClassName,  offset szClassName
          invoke LoadIcon,hInst,500                        ; icon ID
        mov wc.hIcon,          eax
          invoke LoadCursor,NULL,IDC_ARROW
        mov wc.hCursor,        eax
        mov wc.hIconSm,        0

        invoke RegisterClassEx, ADDR wc

        mov Wwd, 400                               ;窗口的宽度
        mov Wht, 300                               ;窗口的高度

        invoke GetSystemMetrics,SM_CXSCREEN
        invoke TopXY,Wwd,eax
        mov Wtx, eax

        invoke GetSystemMetrics,SM_CYSCREEN
        invoke TopXY,Wht,eax
        mov Wty, eax

        szText szClassName,"Template_Class"

invoke CreateWindowEx, WS_EX_CLIENTEDGE,
       ADDR szClassName,
       ADDR szDisplayName,
       WS_POPUP or WS_CAPTION,
       Wtx,Wty,Wwd,Wht,
       NULL,NULL,
       hInst,NULL
       mov   hWnd,eax
                         
INVOKE CreateWindowEx,  WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange01,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
00,90,200,30, hWnd, RadioID01, hInst, NULL
mov hRadio01, eax

INVOKE CreateWindowEx,  WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange02,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
200,90,200,30, hWnd, RadioID02, hInst, NULL
mov hRadio02, eax

INVOKE CreateWindowEx, WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange03,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
00,120,200,30, hWnd, RadioID03, hInst, NULL
mov hRadio01, eax

INVOKE CreateWindowEx,  WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange04,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
200,120,200,30, hWnd, RadioID04, hInst, NULL
mov hRadio02, eax

INVOKE CreateWindowEx, WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange05,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
00,150,200,30, hWnd, RadioID05, hInst, NULL
mov hRadio01, eax

INVOKE CreateWindowEx,  WS_EX_DLGMODALFRAME, CTXT("button"), addr szChange06,\
WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTORADIOBUTTON,\
200,150,200,30, hWnd, RadioID06, hInst, NULL
mov hRadio02, eax
       
        invoke ShowWindow,hWnd,SW_SHOWNORMAL
        invoke UpdateWindow,hWnd

    StartLoop:
      invoke GetMessage,ADDR msg,NULL,0,0
      cmp eax, 0
      je ExitLoop
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage,  ADDR msg
      jmp StartLoop
    ExitLoop:

      return msg.wParam

WinMain endp

; #########################################################################

WndProc proc hWin   :DWORD,
             uMsg   :DWORD,
             wParam :DWORD,
             lParam :DWORD

    LOCAL hDC :DWORD
    LOCAL Ps  :PAINTSTRUCT

    .if uMsg == WM_COMMAND
    mov eax,wParam       
        .IF ax==RadioID01          ;响应按键的动作
        shr eax,16
        .IF ax==BN_CLICKED 
            invoke DecToBin
        .ENDIF
        .ENDIF
       
        .IF ax==RadioID02
        shr eax,16
        .IF ax==BN_CLICKED
           INVOKE BinToDec             
        .ENDIF
        .ENDIF

        .IF ax==RadioID03
        shr eax,16
        .IF ax==BN_CLICKED
            invoke DecToOct
        .ENDIF
        .ENDIF
        .IF ax==RadioID04
        shr eax,16
        .IF ax==BN_CLICKED
            invoke OctToDec
        .ENDIF
        .ENDIF
        .IF ax==RadioID05
        shr eax,16
        .IF ax==BN_CLICKED
        INVOKE DecToHex
        .ENDIF
        .ENDIF
       
        .IF ax==RadioID06
        shr eax,16
        .IF ax==BN_CLICKED
            INVOKE HexToDec           
        .ENDIF
        .ENDIF

           .if wParam == 500                           ;按退出时的响应
           invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
           .endif
      
;***************************************************************************************************
    .elseif uMsg == WM_CREATE       
        szText font1,"黑体"
        invoke CreateFont,20,8,0,0,600,0,0,0, \              ;设置字体
                          DEFAULT_CHARSET,0,0,0,\
                          DEFAULT_PITCH,ADDR font1
        mov hFont, eax                                       ;hFont里存的是字体的句柄
        szText adrTxt,0
        szText lbl3," 数制转换器(二进制 八进制 十进制 十六进制)"
        invoke Static,ADDR lbl3,hWin,00,00,400,30,0 
        szText lbl1,"  ****转换前的数(请输入至多十位正数)****"                   
        invoke Static,ADDR lbl1,hWin,00,30,400,30,0
        szText lbl2,"  ****转换后的数(请输入至多十位正数)****"
        invoke Static,ADDR lbl2,hWin,00,180,400,30,0     
        invoke EditSl,ADDR adrTxt,00,60,500,23,hWin,700                            
        mov hEdit1, eax
        invoke EditSl,ADDR adrTxt,00,210,400,23,hWin,701
        mov hEdit2, eax       
        szText ButnTxt,"退出"
        invoke PushButton,ADDR ButnTxt,hWin,0,240,400,25,500
        mov hButn1, eax
       
        invoke SetTimer,hWin,ID_Timer,500,0             ;定时器 0.5s触发一次
        xor eax,eax
        mov dwNum,eax
        invoke lstrlen,offset szDisplayName            
        mov dwLen,eax
      .elseif uMsg == WM_TIMER
        mov eax,dwNum
        inc eax                                           ;每次加1     
        mov dwNum,eax                                    
        lea eax,szDisplayName
        add eax,dwNum
        invoke lstrcpy,offset szBuf,eax                    ;先将后面的复制过去
        invoke lstrlen,offset szBuf
        lea ecx,szBuf
        add ecx,eax                                        ;指向刚才复制的字符串的末尾
        sub eax,dwLen
        neg eax                                            ;求出剩下的长度
        invoke lstrcpyn,ecx,offset szDisplayName,eax
        mov eax,dwNum
        .if eax >= dwLen                                    ;若当前位置大于长度则重新开始
        xor eax,eax
        mov dwNum,eax
        .endif
        invoke SetWindowText,hWin,offset szBuf

;******************************************************************************************************
    .elseif uMsg == WM_PAINT
        invoke BeginPaint,hWin,ADDR Ps
          mov hDC, eax
          invoke Paint_Proc,hWin,hDC
        invoke EndPaint,hWin,ADDR Ps
        return 0

    .elseif uMsg == WM_NCPAINT                    ;窗口重绘消息
        szText scrn,"DISPLAY"
        invoke CreateDC,ADDR scrn,NULL,NULL,NULL
        mov hDC, eax
        invoke NcPaint_Proc,hWin,hDC
        invoke DeleteDC,hDC
        return 0
    .elseif uMsg == WM_CLOSE

    .elseif uMsg == WM_DESTROY
        invoke PostQuitMessage,NULL
        return 0
    .endif
    invoke DefWindowProc,hWin,uMsg,wParam,lParam
    ret
WndProc endp
;**************************************************************************
;二进制与十进制之间的转换
;**************************************************************************
DecToBin proc
local @szBuffer1[256]:BYTE
local @szBuffer2[256]:BYTE
               invoke GetDlgItemInt,hWnd,EditID01,NULL,FALSE 
               .if eax
               mov ebx,2
               lea esi,@szBuffer1
               xor ecx,ecx
               .while eax!=0
               xor edx,edx
               div ebx
               add edx,'0'
               mov [esi],edx
               inc esi
               inc ecx
               .endw                        ;除2取余 
               lea edi,@szBuffer2                             
               .repeat
               mov edx, [esi-1]
               mov [edi],edx                ;把存在@szBuffer1中的余数反过来存在@szBuffer2 中
               inc edi
               dec esi
               .untilcxz
               mov BYTE ptr [edi],0
              invoke SetDlgItemText, hWnd ,EditID02,addr @szBuffer2
              .else
              invoke SetDlgItemInt, hWnd ,EditID02,eax,TRUE
              .endif
    ret
DecToBin endp

BinToDec proc
local @szBuffer [512]:byte
               invoke GetDlgItemText, hWnd ,EditID01,addr @szBuffer,sizeof @szBuffer
               lea esi,@szBuffer
               cld
               xor eax,eax
               mov ebx,2
               .while TRUE
               movzx ecx,BYTE ptr [esi]
               inc esi
               .break .if !ecx
               .if (ecx>='0')&&(ecx<='1')
                   sub ecx,'0'
                .else
                 invoke MessageBox,hWnd,addr szText1,addr szCaption1, MB_ICONWARNING
                 .break
                 .endif
                mul ebx
                add eax,ecx
               .endw
           invoke SetDlgItemInt, hWnd ,EditID02,eax,TRUE              
    ret
BinToDec endp 
;****************************************************************************************
;八进制与十进制之间的转换
;****************************************************************************************
DecToOct proc
local @szBuffer1[256]:BYTE
local @szBuffer2[256]:BYTE
               invoke GetDlgItemInt,hWnd,EditID01,NULL,FALSE                           
               .if eax
               mov ebx,8
               lea esi,@szBuffer1
               xor ecx,ecx
               .while eax!=0
               xor edx,edx
               div ebx
               add edx,'0'
               mov [esi],edx
               inc esi
               inc ecx
               .endw                        ;除8取余 
               lea edi,@szBuffer2                             
               .repeat
               mov edx, [esi-1]
               mov [edi],edx                ;把存在@szBuffer1中的余数反过来存在@szBuffer2 中
               inc edi
               dec esi
               .untilcxz
               mov BYTE ptr [edi],0
              invoke SetDlgItemText, hWnd ,EditID02,addr @szBuffer2
              .else
              invoke SetDlgItemInt, hWnd ,EditID02,eax,TRUE
              .endif                         
    ret
DecToOct endp

OctToDec proc
local @szBuffer [512]:byte
               invoke GetDlgItemText, hWnd ,EditID01,addr @szBuffer,sizeof @szBuffer
               lea esi,@szBuffer
               cld
               xor eax,eax
               mov ebx,8
               .while TRUE
               movzx ecx,BYTE ptr [esi]
               inc esi
               .break .if !ecx
               .if (ecx>='0')&&(ecx<='8')
                   sub ecx,'0'
                .else
                 invoke MessageBox,hWnd,addr szText2,addr szCaption2, MB_ICONWARNING
                 .break
                 .endif
                mul ebx
                add eax,ecx
               .endw
      lop:     invoke SetDlgItemInt, hWnd ,EditID02,eax,TRUE              
    ret
 OctToDec endp 
;********************************************************************************
;十六进制与十进制之间的转换
;********************************************************************************
DecToHex proc
local @szBuffer [512]:byte
            invoke GetDlgItemInt, hWnd ,EditID01,NULL,FALSE
            invoke wsprintf ,addr @szBuffer,addr szFmtDecToHex,eax
            invoke SetDlgItemText,hWnd,EditID02,addr @szBuffer
            ret
DecToHex endp
HexToDec proc
local @szBuffer [512]:byte
               invoke GetDlgItemText, hWnd ,EditID01,addr @szBuffer,sizeof @szBuffer
               lea esi,@szBuffer
               cld
               xor eax,eax
               mov ebx,16
               .while TRUE
               movzx ecx,BYTE ptr [esi]
               inc esi
               .break .if !ecx              
               .if (ecx>='a')&&(ecx<='f')
                  sub ecx,'a'-0ah
               .elseif(ecx>='A')&&(ecx<='F')
                  sub ecx,'A'-0Ah
               .elseif (ecx>='0')&&(ecx<='9')
                   sub ecx,'0'
               .elseif
                invoke MessageBox,hWnd,addr szText3,addr szCaption3, MB_ICONWARNING
                .break
                .endif
                mul ebx
                add eax,ecx
                .endw
               invoke wsprintf,addr @szBuffer,addr szFmtHexToDec,eax
               invoke SetDlgItemText, hWnd ,EditID02,addr @szBuffer
    ret
  HexToDec endp 

; ########################################################################

TopXY proc wDim:DWORD, sDim:DWORD

    shr sDim, 1      ; divide screen dimension by 2
    shr wDim, 1      ; divide window dimension by 2
    mov eax, wDim    ; copy window dimension into eax
    sub sDim, eax    ; sub half win dimension from half screen dimension
    return sDim
TopXY endp

EditSl proc szMsg:DWORD,a:DWORD,b:DWORD,
               wd:DWORD,ht:DWORD,hParent:DWORD,ID:DWORD
            LOCAL hndle:DWORD
    szText slEdit,"EDIT"
    invoke CreateWindowEx, WS_EX_CONTROLPARENT,ADDR slEdit,szMsg,
                WS_VISIBLE or WS_CHILDWINDOW or \
                ES_AUTOHSCROLL or ES_NOHIDESEL,
              a,b,wd,ht,hParent,ID,hInstance,NULL
            mov hndle, eax
    invoke SendMessage,hndle,WM_SETFONT,hFont,1
           mov eax, hndle
    ret
EditSl endp

Static proc lpText:DWORD,hParent:DWORD,
                 a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,ID:DWORD
            LOCAL hndle:DWORD
         szText statClass,"STATIC"
     invoke CreateWindowEx,WS_EX_DLGMODALFRAME,
            ADDR statClass,lpText,
            WS_CHILD or WS_VISIBLE or SS_LEFT,
            a,b,wd,ht,hParent,ID,
            hInstance,NULL
            mov hndle, eax
    invoke SendMessage,hndle,WM_SETFONT,hFont, 0
    mov eax, hndle
    ret
Static endp

PushButton proc lpText:DWORD,hParent:DWORD,
                a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,ID:DWORD
    LOCAL hndle:DWORD
    szText btnClass,"BUTTON"
    invoke CreateWindowEx,0,
            ADDR btnClass,lpText,
            WS_CHILD or WS_VISIBLE,
            a,b,wd,ht,hParent,ID,
            hInstance,NULL
    mov hndle, eax
    invoke SendMessage,hndle,WM_SETFONT,hFont, 0
    mov eax, hndle
    ret
PushButton endp

; ########################################################################

NcPaint_Proc proc hWin:DWORD,hDC:DWORD

    LOCAL btn_hi   :DWORD
    LOCAL btn_lo   :DWORD
    LOCAL Rct      :RECT

    invoke GetSysColor,COLOR_BTNHIGHLIGHT   ;按钮的3D加亮区
    mov btn_hi, eax

    invoke GetSysColor,COLOR_BTNSHADOW      ;按钮的3D阴影
    mov btn_lo, eax

    invoke GetWindowRect,hWin,ADDR Rct    
;该函数返回指定窗口的边框矩形的尺寸,该尺寸以相对于屏幕坐标左上角的屏幕坐标给出
    add Rct.left, 2                   
    add Rct.top, 2
    sub Rct.right, 2
    sub Rct.bottom, 2

    invoke Frame3D,hDC,btn_hi,btn_lo,
                       Rct.left,Rct.top,
                       Rct.right,Rct.bottom,2

    add Rct.left, 1
    add Rct.top, 1
    sub Rct.right, 1
    sub Rct.bottom, 1

    invoke Frame3D,hDC,btn_lo,btn_hi,
                       Rct.left,Rct.top,
                       Rct.right,Rct.bottom,1

    add Rct.left, 2
    add Rct.top, 2
    sub Rct.right, 2
    sub Rct.bottom, 2

    invoke Frame3D,hDC,btn_hi,btn_lo,
                       Rct.left,Rct.top,
                       Rct.right,Rct.bottom,2

    ret

NcPaint_Proc endp

; #########################################################################

Paint_Proc proc hWin:DWORD, hDC:DWORD
    invoke FrameCtrl,hEdit1,2,1,1
    invoke FrameCtrl,hEdit2,2,1,1   
    invoke FrameCtrl,hButn1,3,1,0
    invoke FrameWindow,hWin,0,1,0
    invoke FrameWindow,hWin,4,1,1
    return 0
Paint_Proc endp
; ########################################################################

end start