کد:
.model small, pascal, nearstack
.286
?WINPROLOGUE = 1
NOKERNEL = 1
NOSOUND = 1
NOCOMM = 1
NODRIVERS = 1
include win.inc ; Converted from WINDOWS.H
;----------------------------------------------------------------------------;
; Prototypes & External Definitions ;
;----------------------------------------------------------------------------;
WinMain PROTO PASCAL, hInstance:HANDLE, hPrevInstance:HANDLE,
lpszCmdLine:LPSTR, nCmdShow:SWORD
WndProc PROTO FAR PASCAL, :HWND, :WORD, :SWORD, :SDWORD
Initialize PROTO, :PINT, :PINT, :PINT, :PINT
Resize PROTO, :HWND
SetupTimer PROTO, :HWND, :WORD
extern __astart:proc ; When Windows load an app, it expects astart
; to have the necessary start-up code. We get
; astart from APPENTRY.ASM
;----------------------------------------------------------------------------;
; Numeric Equates ;
;----------------------------------------------------------------------------;
INIT_FONT EQU 30t ; initial font height
MAX_HEIGHT EQU 100 ; Maximum Font Height
TOP_CORNER EQU 1 ; Set to 0 for Lower-Right Corner Clock
IDM_DATE EQU 1t ; definitions for Menu items
IDM_ALARM EQU 2t
IDM_SET EQU 3t
IDM_MENU EQU 4t
IDM_EXIT EQU 5t
IDM_ABOUT EQU 6t
IDM_MINIMIZE EQU 7t
IDM_ONTOP EQU 8t
AMPM EQU 3t ; length of am/pm strings
SCROLLCHILD EQU 30t ; identifies scroll: any number will do
MAXTIME EQU 1439t ; max # of minutes
TIMER_SECS EQU 1000t ; timer interval: 1000 mill = 1 second
TIMER_MINS EQU 60000t ; interval for 1 minute: 1000 * 60
ICON_LEN EQU 7t ; # of chars to display icon time
;----------------------------------------------------------------------------;
; Data Segments ;
;----------------------------------------------------------------------------;
.const
szAppName SBYTE "WINClock",0
DateFmt SBYTE " %s %2d, %04d ",13,10,0
TimeFmt SBYTE " %d:%02d:%02d %s ",0
IconFmt SBYTE " %d:%02d ",0
AlarmFmt SBYTE " %d:%02d %s ",0
szAMPM SBYTE "am",0,"pm",0
szTooManyTimers SBYTE "Too many clocks or timers!",0
szAlarmMsg SBYTE "Remember your Appointment!",0
szMonths SBYTE "Jan",0,"Feb",0,"Mar",0,"Apr",0,"May",0,"Jun",0,
"Jul",0,"Aug",0,"Sep",0,"Oct",0,"Nov",0,"Dec",0
szDateCmd SBYTE "Enable &Date", 0
szSetCmd SBYTE "S&et Alarm",0
szAlarmCmd SBYTE "Enable &Alarm", 0
szOnTopCmd SBYTE "Always on &Top",0
szMinimizeCmd SBYTE "&Minimize", 0
szExitCmd SBYTE "E&xit", 0
szAboutCmd SBYTE "About &Clock...", 0
szAboutText SBYTE "Assembler Program Using the Windows API", 0
szDisplay SBYTE "DISPLAY", 0 ; to get a handle to entire display
szScrollBar SBYTE "scrollbar", 0 ; to create scrollbar 'class'
.data
EnableDate BYTE MF_CHECKED ; Date initially enabled
EnableAlarm BYTE MF_UNCHECKED ; Alarm initially disabled
AlwaysOnTop BYTE MF_CHECKED ; Window will be on topmost
Iconized BYTE FALSE ; Clock initially Normal Size
TestAlarm BYTE FALSE ; so that we know to test for the alarm
SetAlarm BYTE FALSE ; signalling while we set the alarm
AlarmTime WORD (MAXTIME/2)+1 ; initial alarm time: 12:00 pm
.data?
cBuffer SBYTE 40 dup (?) ; buffer to receive text for drawing
hMenu HMENU ? ; handle to Popup Menu
logfont LOGFONT { } ; logical font structure
hWndScrol HWND ? ; handle to the scroll window
TextRect RECT { } ; rectangle to draw text in
;----------------------------------------------------------------------------;
; Code Segment ;
;----------------------------------------------------------------------------;
.code
;----------------------------------------------------------------------------;
; WinMain ;
;----------------------------------------------------------------------------;
; ;
; Main routine called by Windows in program start. If no previous instances, ;
; sets up a window class and registers it. Initializes the program with ;
; Initialize, creates a top window with the coordinates from Initialize, sets;
; up a child scroll bar control, and sets up the message loop. ;
; ;
;----------------------------------------------------------------------------;
WinMain PROC, hInstance:HANDLE, hPrevInstance:HANDLE,
lpszCmdLine:LPSTR, nCmdShow:SWORD
LOCAL msg:MSG, wndclass:WNDCLASS, xStart:SWORD,
yStart:SWORD, xClient:SWORD, yClient:SWORD
; Local variables: msg: message to be used in the message loop
; wndclass: temp. to store window class
; x,y Start-Client: Size of Initial Window
;
;--- Check for previous instances
;
.IF (hPrevInstance == 0)
lea di, wndclass ; because we use a NEARSTACK,
ASSUME di:PTR WNDCLASS ; ss=ds
mov ax, CS_HREDRAW OR CS_VREDRAW OR CS_DBLCLKS
mov [di].style, ax
mov WORD PTR [di].lpfnWndProc, LROFFSET WndProc
mov WORD PTR [di].lpfnWndProc+2, SEG WndProc
xor ax,ax
mov [di].cbClsExtra, ax
mov [di].cbWndExtra, ax
mov [di].hIcon, ax ; null icon: we will draw it
mov ax, hInstance
mov [di].hInstance, ax
INVOKE LoadCursor, NULL, IDC_ARROW
mov [di].hCursor, ax
INVOKE GetStockObject, WHITE_BRUSH
mov [di].hbrBackground, ax
xor ax, ax
mov WORD PTR [di].lpszMenuName, ax
mov WORD PTR [di].lpszMenuName+2, ax
mov WORD PTR [di].lpszClassName, OFFSET szAppName
mov WORD PTR [di].lpszClassName+2, ds
INVOKE RegisterClass, di
.IF (ax == 0)
mov ax, FALSE
jmp doRet
.ENDIF
ASSUME di:NOTHING
.ENDIF ;--- End of IF (hPrevInstance == 0)
;
;---- Initialize
;
INVOKE Initialize, ADDR xStart, ADDR yStart,
ADDR xClient, ADDR yClient
;
;---- Create Top Window
;
INVOKE CreateWindowEx, WS_EX_TOPMOST, ADDR szAppName,
ADDR szAppName, WS_BORDER OR WS_POPUP OR WS_THICKFRAME,
xStart, yStart, xClient, yClient, NULL, NULL,
hInstance, NULL
mov si, ax ; keep hWnd in SI, since SI doesn't
; change after function calls
INVOKE ShowWindow, si, SW_SHOWNOACTIVATE
INVOKE UpdateWindow, si
;
;----Create Scroll Child Window
;
INVOKE CreateWindow, ADDR szScrollBar, NULL,
WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR SBS_HORZ,
0, 0, 0, 0, si, SCROLLCHILD, hInstance, NULL
mov hWndScrol, ax
INVOKE SetScrollRange, ax, SB_CTL, 0, MAXTIME, FALSE
INVOKE SetScrollPos, hWndScrol, SB_CTL, AlarmTime, FALSE
INVOKE ShowScrollBar, hWndScrol, SB_CTL, TRUE
INVOKE ShowWindow, hWndScrol, SW_SHOWNOACTIVATE
INVOKE UpdateWindow, hWndScrol
;
;---- Message Loop
;
.WHILE TRUE
INVOKE GetMessage, ADDR msg, NULL, 0, 0
.BREAK .IF (ax == 0)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
;
;---- Return to Windows
;
mov ax, msg.wParam
doRet:
ret
WinMain ENDP
;----------------------------------------------------------------------------;
; Initialize ;
;----------------------------------------------------------------------------;
; ;
; Initializes the logfont struct, sizes the Initial Window, Makes the Menu. ;
; ;
; For the size of the initial window: We get the DC for the entire display, ;
; and calculate the size of the font into tmetric. With that, we allow for ;
; the necessary distance from the top right corner so that there's enough ;
; space for the text. ;
; ;
;----------------------------------------------------------------------------;
Initialize PROC USES si di, pxStart:PINT, pyStart:PINT,
pxClient:PINT, pyClient:PINT
; px,py,Start,Client will hold the dimensions of the initial
; window to create
LOCAL hFont:HFONT, hDC:HDC, tmetric:TEXTMETRIC
; locals: a handle to a font, one to a device context,
; and a textmetric structure
;
;---- Initialize the logfont structure
;
mov bx, OFFSET logfont
ASSUME bx:PTR LOGFONT
xor ax, ax
mov [bx].lfHeight, INIT_FONT; Initial Font Height
mov [bx].lfWidth, ax ; width's set according to hght
mov [bx].lfEscapement, ax
mov [bx].lfOrientation, ax
mov [bx].lfWeight, FW_NORMAL
mov [bx].lfItalic, al
mov [bx].lfUnderline, al
mov [bx].lfStrikeOut, al
mov [bx].lfCharSet, ANSI_CHARSET
mov [bx].lfOutPrecision, al
mov [bx].lfClipPrecision, al
mov [bx].lfQuality, al
mov [bx].lfPitchAndFamily, DEFAULT_PITCH OR FF_SWISS
mov [bx].lfFaceName, NULL
ASSUME bx:NOTHING
;---- Get Initial Size for the Window Based on Font
xor dx, dx
INVOKE CreateIC, ADDR szDisplay, dx::dx, dx::dx, dx::dx
mov hDC, ax
INVOKE CreateFontIndirect, ADDR logfont
mov hFont, ax
INVOKE SelectObject, hDC, ax
mov hFont, ax
INVOKE GetTextMetrics, hDC, ADDR tmetric
INVOKE SelectObject, hDC, hFont
INVOKE DeleteObject, ax
INVOKE DeleteDC, hDC
INVOKE GetSystemMetrics, SM_CXDLGFRAME ; Set window width
shl ax, 1 ; frame*2
mov bx, tmetric.tmAveCharWidth ; width of font
mov cl, 4 ; to shift
shl bx, cl ; width*16
add ax, bx ; frame*2 + width*16
mov si, pxClient ; address to store in
mov [si], ax ; store
INVOKE GetSystemMetrics, SM_CXSCREEN ; screen x-length
mov si, pxClient ; window width
sub ax, [si] ; start=corner-winWdth
mov si, pxStart ; store result
mov [si], ax
INVOKE GetSystemMetrics, SM_CYDLGFRAME ; Set Height
shl ax, 1 ; frame*2
mov bx, tmetric.tmHeight ; height*2
shl bx, 1
add ax, bx ; add
mov si, pyClient ; store in pyClient
mov [si], ax
IF TOP_CORNER ; if Top Corner,
xor ax, ax ; yStart=0
ELSE ; else,
INVOKE GetSystemMetrics, SM_CYSCREEN
mov si, pyClient ; yStart = ScreenHgth
sub ax, [si] ; minus yHeight
ENDIF
mov si, pyStart ; set yStart
mov [si], ax
;
;---- Initialize the Menu
;
INVOKE CreatePopupMenu
mov hMenu, ax
; Date is Initially Enabled
INVOKE AppendMenu, hMenu, MF_STRING OR MF_CHECKED, IDM_DATE,
ADDR szDateCmd
INVOKE AppendMenu, hMenu, MF_STRING, IDM_ALARM,ADDR szAlarmCmd
INVOKE AppendMenu, hMenu, MF_STRING, IDM_SET, ADDR szSetCmd
INVOKE AppendMenu, hMenu, MF_SEPARATOR, 0, NULL
INVOKE AppendMenu, hMenu, MF_STRING OR MF_CHECKED, IDM_ONTOP,
ADDR szOnTopCmd
INVOKE AppendMenu, hMenu, MF_STRING, IDM_MINIMIZE,
ADDR szMinimizeCmd
INVOKE AppendMenu, hMenu, MF_STRING, IDM_EXIT, ADDR szExitCmd
INVOKE AppendMenu, hMenu, MF_SEPARATOR, 0, NULL
INVOKE AppendMenu, hMenu, MF_STRING, IDM_ABOUT,ADDR szAboutCmd
ret
Initialize ENDP
;----------------------------------------------------------------------------;
; SetupTimer ;
;----------------------------------------------------------------------------;
; ;
; Setup a timer with the specified interval. If we can't set up the timer, ;
; output a message box and exit the program. ;
;----------------------------------------------------------------------------;
SetupTimer PROC NEAR, hWnd:HWND, Interval:WORD
; hWnd is the Handle of the Window to associate the timer with
; Interval is the interval in milliseconds
INVOKE SetTimer, hWnd, 1, Interval, NULL
.IF (ax == 0)
INVOKE MessageBox, hWnd,ADDR szTooManyTimers,
ADDR szAppName,
MB_ICONEXCLAMATION OR MB_OK
mov ax, FALSE
INVOKE PostQuitMessage, 0 ; Quit.
.ENDIF
ret
SetupTimer ENDP
;----------------------------------------------------------------------------;
; AlarmSetup ;
;----------------------------------------------------------------------------;
; ;
; If we're going to set the alarm, kill the timer, show the scroll bar, and ;
; resize the fonts. Enable the Alarm after it has been re-set. ;
; ;
; If we just set up the alarm, get a new timer, ;
; check the menu to enable the alarm, hide the scrollbar, resize the fonts ;
; When creating the top window this is called to set up the initial timer. ;
; ;
;----------------------------------------------------------------------------;
AlarmSetup PROC, hWnd:HWND
; hWnd is the handle of the window that received WinPaint
.IF SetAlarm
INVOKE KillTimer, hWnd, 1
INVOKE Resize, hWnd
INVOKE ShowScrollBar, hWndScrol, SB_CTL, TRUE
INVOKE SetFocus, hWndScrol
INVOKE InvalidateRect, hWnd, NULL, TRUE
mov EnableAlarm, MF_CHECKED
mov TestAlarm, TRUE
.ELSE
INVOKE SetupTimer, hWnd, TIMER_SECS
INVOKE CheckMenuItem, hMenu, IDM_ALARM, EnableAlarm
INVOKE ShowScrollBar, hWndScrol, SB_CTL, FALSE
INVOKE Resize, hWnd
INVOKE InvalidateRect, hWnd, NULL, TRUE
.ENDIF
ret
AlarmSetup ENDP
;----------------------------------------------------------------------------;
; Resize ;
;----------------------------------------------------------------------------;
; ;
; Simple resizing, without taking into account aspect ratio. ;
; If we're setting the alarm, the scroll bar height will be (client hgt)/16, ;
; the length will be (client lenght)-(2*Scroll Bar Height), and the top will ;
; will start (in Client coordinates), at one SB Height right and 2 SBHeights ;
; up from the left bottom corner. Fonts width will be length/10, height will ;
; be (client height)-(3*Scroll bar height). The Scroll bar is also displayed.;
; ;
; If we're not setting the alarm, and we're not minimized, font width will be;
; length/TIME_LEN and height will be either client height or client height/2,;
; depending on the date being enabled or not. ;
; ;
; If font height is more than MAX_HEIGHT, then height is MAX_HEIGHT, and the ;
; TextRect.top is computed so that Drawing the text on the client area will ;
; be centered. ;
; ;
; If we're minimized, width=length/ICON_LEN, height is client height. ;
; ;
; The TextRect is used so that it's not recomputed everytime the Window is ;
; repainted. ;
; ;
;----------------------------------------------------------------------------;
Resize PROC, hWnd:HWND
; hWnd is the handle of the window that received WinPaint
LOCAL rect:RECT
; holds a rectangle structure
INVOKE SetFocus, hWnd ; take focus out of child window
INVOKE GetClientRect, hWnd, ADDR rect ; get new rect.size
;---- Find desired Text Height
.IF SetAlarm
;---- Calculate New TextRect allowing for Scroll Bar
mov bx, rect.bottom ; SXstart is length / 8
shr bx, 3
mov cx, rect.right ; SLength=CLenght-2*SHeight
sub cx, bx
sub cx, bx
mov dx, rect.bottom ; SYstart will be CHgt-2*SHgt
sub dx, bx
sub dx, bx
mov TextRect.bottom, dx ; bottom = CHgt - 3*SHgt
sub TextRect.bottom, bx
INVOKE MoveWindow, hWndScrol, bx, dx, cx, bx, FALSE
INVOKE SetScrollPos,hWndScrol,SB_CTL,AlarmTime,TRUE
mov ax,TextRect.bottom ; Try to use Full Height
; for font height
;---- Else (not setting the alarm)
.ELSE
mov ax, rect.bottom ; Full or Half Height
mov TextRect.bottom, ax
.IF EnableDate && !Iconized
shr ax, 1 ; height/2
.ENDIF
.ENDIF
;---- Test if desired height is allowed or not
;---- If height>MAX, then height=MAX_HEIGHT. Adjust TextRect.top by
;---- substracting from the bottom the font height (or twice that if Date),
;---- dividing by two, and adding to the TextRect.top.
.IF (ax > MAX_HEIGHT)
mov logfont.lfHeight, MAX_HEIGHT
mov ax, TextRect.bottom
mov bx, MAX_HEIGHT
.IF EnableDate && !Iconized
shl bx, 1
.ENDIF
sub ax, bx
shr ax, 1
mov TextRect.top, ax
.ELSE
mov logfont.lfHeight, ax
mov TextRect.top, 0
.ENDIF
mov TextRect.left, 0 ; Left is Zero
mov ax, rect.right ; Same Rect length
mov TextRect.right, ax
;---- Set font width according to Iconized or not.
.IF Iconized
xor dx, dx
mov bx, ICON_LEN
div bx
.ELSE
shr ax, 4 ; length/16
.ENDIF
mov logfont.lfWidth, ax
ret
Resize ENDP
;----------------------------------------------------------------------------;
; PaintAlarm ;
;----------------------------------------------------------------------------;
; ;
; Painting the alarmtime. Get the hours and minutes from Alarmtime, get AM ;
; or PM by going into szAMPM either at 0 or 3, to get the appropiate string. ;
; Then we simply draw the text into the TextRect calculated by Resize, with ;
; the font that we get from using the logfont structure. ;
; ;
;----------------------------------------------------------------------------;
PaintAlarm PROC USES si di, hWnd:HWND, hDC:HDC
; hWnd is the handle of the window that received WinPaint
; hDC is the Device context of the window
LOCAL nLength:SWORD, hFont:HFONT,
hour:WORD, minutes:WORD, seconds:WORD
; Locals: nLength is the current length of the buffer
; hFont is a handle to a font.
;---- Get Time from AlarmTime
xor dx, dx
mov ax, AlarmTime
mov bx, 60t
div bx ; ax holds the hours
mov bx, dx ; bx holds the minutes
mov si, ax ; si holds the hours
xor dx, dx
mov di, 12
div di ; will have ax=0 or 1 (am/pm)
xor dx, dx
mov cx, AMPM ; AMPM = 3: 'am'+\0
mul cx
mov di, ax
add di,offset szAMPM ; get into di the correct
; memory address
mov ax, si ; ax == tm_hour
xor dx, dx
mov cx, 12
div cx
.IF (dx == 0) ; so we don't have 00:45
mov cx, 12
.ELSE
mov cx, dx
.ENDIF
;---- on using wsprintf below: since the wsprintf prototype has VARARG,
;---- we can't tell the assemble the distance of those arguments, so we
;---- have to do a specific far pointer to the data. wsprintf expects all
;---- pointers to be far pointers, no exceptions.
INVOKE wsprintf, ADDR cBuffer, ADDR AlarmFmt,
cx, bx, ds::di
mov nLength,ax
;---- Set Font & Draw Text
INVOKE CreateFontIndirect, ADDR logfont
mov hFont, ax
INVOKE SelectObject, hDC, ax
mov hFont, ax
INVOKE DrawText, hDC, ADDR cBuffer, nLength, ADDR TextRect,
(DT_CENTER)
INVOKE SelectObject, hDC, hFont
INVOKE DeleteObject, ax
ret
PaintAlarm ENDP
;----------------------------------------------------------------------------;
; PaintTime ;
;----------------------------------------------------------------------------;
; ;
; Painting the time. We get a index to szMonths by multiplying the [0-11] ;
; month by 4 ('jan'+\0). We print everything to a string and store the length;
; as an index. We do this only if Date's enabled. ;
; For the time, we do the same AM/PM thing as in PaintAlarm, and print it to ;
; the same string after the Date's carriage return (included in DateFmt. ;
; Then we simply draw the text into the TextRect calculated by Resize, with ;
; the font that we get from using the logfont structure. ;
; If we're minimized, we also draw a rectangle around the time. We get a pen ;
; of width 2, black, and a hollow (transparent) brush. We save the pen ID in ;
; the stack so that we can deselect it later. ;
; Then, we check to see if we have to spring the alarm. If TestAlarm is not ;
; enabled, check the time and re-enable TestAlarm if it's NOT the AlarmTime ;
; (i.e. so that after we ring it it will ring in 24 hours). If TestAlarm is ;
; set, check if EnableAlarm is set. If it is, multiply the hours by 60, add ;
; the minutes, compare with AlarmTime. Notice that the 'mov bx, datetime' is ;
; necessary because the wsprintf and DrawText will trash ax, bx, cx. If it's ;
; alarm time, disable TestAlarm, invert the rectangle, sound a beep, revert ;
; the rect, and do a message box. This way, TestAlarm enables us to always ;
; have at least one check of the alarm time. ;
; ;
;----------------------------------------------------------------------------;
PaintTime PROC USES si di, hWnd:HWND, hDC:HDC
; hWnd is the handle of the window that received WinPaint
; hDC is the Device context of the window
LOCAL nLength:SWORD, hFont:HFONT, pen:WORD,
hour:WORD, minutes:WORD, seconds:WORD
; Locals: nLength is the current length of the buffer
; hFont is a handle to a font.
;---- Set Date Variables
.IF (EnableDate && !Iconized)
mov ah, 2Ah ; function: Get Date
INVOKE DOS3Call ; do the interrupt
; dh will have months
; dl will have days
; cx will have years
mov al, dh ; months (1-12)
xor ah, ah
xor dh, dh ; day-of-month (1-31)
mov si, ax ; (Month-1) * 4
dec si
shl si, 2
add si, offset szMonths
;---- For note on wsprintf below, see PaintAlarm
INVOKE wsprintf, ADDR cBuffer, ADDR DateFmt,
ds::si, dx, cx
mov nLength, ax
.ELSE
mov nLength, 0
.ENDIF ; of EnableDate
;---- Get Time from CPU clock
xor dx, dx
mov ah, 2Ch ; function: Get Time
INVOKE DOS3Call ; do the interrupt
; ch will have hours
; cl will have minutes
; dh will have seconds
mov al, ch ; hours (0-23)
xor ah, ah
mov hour, ax
mov al, cl ; minutes (0-59)
mov minutes, ax
mov al, dh ; seconds (0-59)
mov seconds, ax
mov ax, hour ; divide hour/12, multiply
xor dx, dx ; by 3 to get offset into
mov bx, 12 ; szAMPM, then add the
div bx ; szAMPM offset
mov si, dx ; dx would have hours
xor dx, dx
mov cx, AMPM
mul cx
mov bx, ax
add bx, offset szAMPM ; get into di the correct
; memory address
.IF (si == 0) ; get hour into cx
mov cx, 12 ; or 12 if hour=0
.ELSE
mov cx, si
.ENDIF
mov si, nLength
.IF !Iconized
INVOKE wsprintf, ADDR cBuffer[si], ADDR TimeFmt,
cx, minutes, seconds, ds::bx
.ELSE
INVOKE wsprintf, ADDR cBuffer[si], ADDR IconFmt,
cx, minutes
.ENDIF
add nLength, ax
;---- Set Font, Draw the Text
INVOKE CreateFontIndirect, ADDR logfont
mov hFont, ax
INVOKE SelectObject, hDC, ax
mov hFont, ax
INVOKE DrawText, hDC, ADDR cBuffer, nLength, ADDR TextRect,
DT_NOCLIP OR DT_CENTER
INVOKE SelectObject, hDC, hFont
INVOKE DeleteObject, ax
;---- If Iconized, draw rectangle with transparent background
.IF Iconized
INVOKE GetStockObject, HOLLOW_BRUSH
INVOKE SelectObject, hDC, ax
INVOKE CreatePen, PS_SOLID OR PS_INSIDEFRAME, 2, 0
INVOKE SelectObject, hDC, ax
push ax
INVOKE Rectangle, hDC, TextRect.left, TextRect.top,
TextRect.right, TextRect.bottom
INVOKE GetStockObject, HOLLOW_BRUSH
INVOKE SelectObject, hDC, ax
INVOKE DeleteObject, ax
pop ax
INVOKE SelectObject, hDC, ax
INVOKE DeleteObject, ax
.ENDIF
;---- Check for Alarm
xor dx, dx
mov ax, hour
mov cx, 60t
imul cx
add ax, minutes ; ax now holds the time in minutes
.IF (TestAlarm)
.IF (EnableAlarm && (ax == AlarmTime))
mov TestAlarm, FALSE
INVOKE SetFocus, hWnd
INVOKE InvertRect, hDC, ADDR TextRect
INVOKE MessageBeep, MB_ICONASTERISK
INVOKE InvertRect, hDC, ADDR TextRect
INVOKE MessageBox, hWnd, ADDR szAlarmMsg,
ADDR szAppName,MB_ICONEXCLAMATION OR MB_OK
.ENDIF
.ELSE ; of TestAlarm ; if TestAlarm=0, means
.IF (ax != AlarmTime) ; we sounded the alarm.
mov TestAlarm, TRUE ; but, if time
.ENDIF ; changed, we should to
.ENDIF ; check again (allows
; alarm every 24 hours)
ret
PaintTime ENDP
WndProc PROC FAR PASCAL, hWnd:HWND, iMessage:WORD, wParam:SWORD,
lParam:SDWORD
; Windows gives us: the handle of the Window, the Message ID,
; and two parameters for the message
LOCAL hDC:HDC, ps:PAINTSTRUCT, point:POINT
; locals: a handle to a device context, a paint structure,
; a point structure
.IF (iMessage == WM_CREATE)
INVOKE SetupTimer, hWnd, TIMER_SECS
INVOKE Resize, hWnd
INVOKE InvalidateRect, hWnd, NULL, FALSE
.ELSEIF (iMessage == WM_TIMER)
INVOKE InvalidateRect, hWnd, NULL, FALSE
.ELSEIF (iMessage == WM_PAINT)
INVOKE BeginPaint, hWnd, ADDR ps
mov hDC, ax
.IF SetAlarm
INVOKE PaintAlarm, hWnd, hDC
.ELSE
INVOKE PaintTime, hWnd, hDC
.ENDIF
INVOKE EndPaint, hWnd, ADDR ps
.ELSEIF (iMessage == WM_SETFOCUS)
INVOKE RedrawWindow, hWnd, NULL, NULL,
RDW_FRAME OR RDW_UPDATENOW
.ELSEIF (iMessage == WM_SIZE)
.IF ((wParam != SIZE_MINIMIZED) && Iconized)
mov Iconized, FALSE
INVOKE KillTimer, hWnd, 1
INVOKE SetupTimer, hWnd, TIMER_SECS
.ENDIF
INVOKE Resize, hWnd
INVOKE RedrawWindow, hWnd, NULL, NULL,
RDW_ERASE OR RDW_INVALIDATE
.ELSEIF (iMessage == WM_DESTROY)
INVOKE KillTimer, hWnd, 1
INVOKE PostQuitMessage, 0
.ELSEIF (iMessage==WM_LBUTTONDBLCLK)||(iMessage==WM_RBUTTONUP)
.IF SetAlarm
xor SetAlarm, TRUE
INVOKE AlarmSetup, hWnd
.ELSE
mov di, word ptr lParam
mov point.x, di
mov di, word ptr (lParam+2)
mov point.y, di
INVOKE ClientToScreen, hWnd, ADDR point
INVOKE TrackPopupMenu, hMenu, TPM_LEFTALIGN,
point.x, point.y, 0, hWnd, NULL
INVOKE InvalidateRect, hWnd, NULL, TRUE
.ENDIF
.ELSEIF (iMessage == WM_LBUTTONDOWN)
INVOKE DefWindowProc, hWnd, WM_NCLBUTTONDOWN,
HTCAPTION, lParam
.ELSEIF (iMessage == WM_COMMAND)
.IF (wParam == IDM_DATE)
xor EnableDate, MF_CHECKED
INVOKE CheckMenuItem,hMenu,wParam,EnableDate
INVOKE Resize, hWnd
INVOKE InvalidateRect, hWnd, NULL, FALSE
.ELSEIF (wParam == IDM_ALARM)
xor EnableAlarm, MF_CHECKED
mov TestAlarm, TRUE
INVOKE CheckMenuItem,hMenu,wParam,EnableAlarm
.ELSEIF (wParam == IDM_SET)
mov SetAlarm, TRUE
INVOKE AlarmSetup, hWnd
.ELSEIF (wParam == IDM_ABOUT)
INVOKE MessageBox, hWnd, ADDR szAboutText,
ADDR szAppName, MB_ICONASTERISK OR MB_OK
.ELSEIF (wParam == IDM_ONTOP)
xor AlwaysOnTop, MF_CHECKED
INVOKE CheckMenuItem,hMenu,wParam,AlwaysOnTop
.IF AlwaysOnTop
mov ax, HWND_TOPMOST
.ELSE
mov ax, HWND_NOTOPMOST
.ENDIF
INVOKE SetWindowPos, hWnd, ax,
0, 0, 0, 0, SWP_NOMOVE OR SWP_NOSIZE
.ELSEIF (wParam == IDM_EXIT)
INVOKE KillTimer, hWnd, 1
INVOKE PostQuitMessage, 0
.ELSEIF (wParam == IDM_MINIMIZE)
mov Iconized, TRUE
INVOKE KillTimer, hWnd, 1
INVOKE SetupTimer, hWnd, TIMER_MINS
INVOKE DefWindowProc, hWnd, WM_SYSCOMMAND,
SC_ICON, NULL
.ENDIF
.ELSEIF (iMessage == WM_HSCROLL)
.IF (wParam == SB_PAGEDOWN)
add AlarmTime, 10t
.ELSEIF (wParam == SB_LINEDOWN)
inc AlarmTime
.ELSEIF (wParam == SB_PAGEUP)
sub AlarmTime, 10t
.ELSEIF (wParam == SB_LINEUP)
dec AlarmTime
.ELSEIF (wParam == SB_TOP)
mov AlarmTime, MAXTIME
.ELSEIF (wParam == SB_BOTTOM)
mov AlarmTime, 0t
.ELSEIF (wParam == SB_THUMBPOSITION)
mov ax, word ptr lParam
mov AlarmTime, ax
.ELSEIF (wParam == SB_THUMBTRACK)
mov ax, word ptr lParam
mov AlarmTime, ax
.ELSEIF (wParam == SB_LINEDOWN)
mov ax, word ptr lParam
mov AlarmTime, ax
.ENDIF
.IF (AlarmTime < 0)
mov AlarmTime, 0t
.ELSEIF (AlarmTime > MAXTIME)
mov AlarmTime, MAXTIME
.ENDIF
INVOKE SetScrollPos, hWndScrol, SB_CTL,
AlarmTime, TRUE
INVOKE InvalidateRect, hWnd,
ADDR TextRect, FALSE
.ELSE
INVOKE DefWindowProc, hWnd, iMessage,
wParam,lParam
jmp doRet
.ENDIF
mov ax, 0
cwd
doRet:
ret
WndProc ENDP
END __astart ; so that the code of the application will
; start with the Windows start-up code
اما شما می توانید یک بخش بحرانی برنامه را فقط با Assembly بنویسید.
void add(unsigned ling int X, unsigned long int Y, unsigned long int& intResult)0
اما مواظب باش حتی الآمکان از Assmbely در برنامه هات استفاده نکن.