Download the example here.
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include
\masm32\include\windows.inc
include
\masm32\include\user32.inc
include
\masm32\include\kernel32.inc
includelib
\masm32\lib\user32.lib
includelib
\masm32\lib\kernel32.lib
.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(?)
; 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:DWORD
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 hInst
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,eax
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
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain
endp
WndProc
proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==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 BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==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 uMsg==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.