.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "My First Button",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?),0
; buffer to store the text retrieved from the edit box
.const
ButtonID equ 1
; The control ID of the button control
EditID equ 2
; The control ID of the edit control
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,0
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,
\
ADDR AppName, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT, CW_USEDEFAULT,\
300,200,NULL,NULL, hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR
msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
; Translate the raw keyboard input into character
input
invoke DispatchMessage,
ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
mov eax,uMsg
.IF eax==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF eax==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,35,200,25,hWnd,8,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or ES_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.IF lParam==0
Recall that a menu also sends WM_COMMAND messages
to notify the window about its state too. How can you differentiate between
WM_COMMAND messages originated from a menu or a control? Below is the answer
Low word of wParam | High word of wParam | lParam | |
Menu | Menu ID | 0 | 0 |
Control | Control ID | Notification code | Child Window Handle |
You can see that you should check lParam. If it's zero, the current WM_COMMAND message is from a menu. You cannot use wParam to differentiate between a menu and a control since the menu ID and control ID may be identical and the notification code may be zero.
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
You can put a text string into an edit box by
calling SetWindowText. You clear the content of an edit box by calling
SetWindowText with NULL. SetWindowText is a general purpose API function.
You can use SetWindowText to change the caption of a window or the text
on a button.
To get the text in an edit box, you use GetWindowText.
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
The above code snippet deals with the condition
when the user presses the button. First, it checks the low word of wParam
to see if the control ID matches that of the button. If it is, it checks
the high word of wParam to see if it is the notification code BN_CLICKED
which is sent when the button is clicked.
The interesting part is after it's certain that
the notification code is BN_CLICKED. We want to get the text from the edit
box and display it in a message box. We can duplicate the code in the IDM_GETTEXT
section above but it doesn't make sense. If we can somehow send a WM_COMMAND
message with the low word of wParam containing the value IDM_GETTEXT to
our own window procedure, we can avoid code duplication and simplify our
program. SendMessage function is the answer. This function sends any message
to any window with any wParam and lParam we want. So instead of duplicating
the code, we call SendMessage with the parent window handle, WM_COMMAND,
IDM_GETTEXT, and 0. This has identical effect to selecting "Get Text" menu
item from the menu. The window procedure doesn't perceive any difference
between the two.
You should use this technique as much as possible
to make your code more organized.
Last but not least, do not forget the TranslateMessage
function in the message loop. Since you must type in some text into the
edit box, your program must translate raw keyboard input into readable
text. If you omit this function, you will not be able to type anything
into your edit box.