I was looking for example programs to learn about window based application with Assembly language
Then i found this
Since this is the first time i am trying to make a window based application , I don't even know where to start .
Can someone explain this program to me ?
; #########################################################################
.386
.model flat, stdcall
option casemap :none
; #########################################################################
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
; #########################################################################
szText macro name, text:vararg
local lbl
jmp lbl
name db text, 0
lbl:
endm
WinMain proto :dword, :dword, :dword, :dword
WndProc proto :dword, :dword, :dword, :dword
; #########################################################################
.data
hInstance dd ?
lpszCmdLine dd ?
; #########################################################################
.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov lpszCmdLine, eax
invoke WinMain, hInstance, NULL, lpszCmdLine, SW_SHOWDEFAULT
invoke ExitProcess, eax
; ------------------------------------------------------------------------
; WinMain
;
; Main program execution entry point
; ------------------------------------------------------------------------
WinMain proc hInst :dword,
hPrevInst :dword,
szCmdLine :dword,
nShowCmd :dword
local wc :WNDCLASSEX
local msg :MSG
local hWnd :HWND
szText szClassName, "BasicWindow"
szText szWindowTitle, "First Window"
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW
mov wc.lpfnWndProc, WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground, COLOR_BTNFACE + 1
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset szClassName
invoke LoadIcon, hInst, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
invoke LoadCursor, hInst, IDC_ARROW
mov wc.hCursor, eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx, WS_EX_APPWINDOW, addr szClassName, addr szWindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInst, NULL
mov hWnd, eax
invoke ShowWindow, hWnd, nShowCmd
invoke UpdateWindow, hWnd
MessagePump:
invoke GetMessage, addr msg, NULL, 0, 0
cmp eax, 0
je MessagePumpEnd
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
jmp MessagePump
MessagePumpEnd:
mov eax, msg.wParam
ret
WinMain endp
; ------------------------------------------------------------------------
; WndProc
;
; Handles all of the messages sent to the window
; ------------------------------------------------------------------------
WndProc proc hWin :dword,
uMsg :dword,
wParam :dword,
lParam :dword
.if uMsg == WM_DESTROY
invoke PostQuitMessage, 0
xor eax, eax
ret
.endif
invoke DefWindowProc, hWin, uMsg, wParam, lParam
ret
WndProc endp
end start
Google for RegisterClassEx CreateWindowEx GetMessage to see 154,000 pages explaining how it works.
Of course, somebody could sit down and write another tutorial especially for you. How much are you willing to pay?
Sorry about that , i have to google a lot of things in that program
Thanks for the keywords .
Hi sunshine33,
You would like to study Iczelion's Tutorial 3, A Simple Window, that's what you are looking for :
http://win32assembly.programminghorizon.com/tut3.html
Quote from: Vortex on April 15, 2018, 03:10:25 AM
Hi sunshine33,
You would like to study Iczelion's Tutorial 3, A Simple Window, that's what you are looking for :
Excellent idea.
Full selection of iczelions tutorials found here. I suggest you start with "The Basics" tut 1, under the heading "Win 32 Assembly"
edit = removed broken link. iczelions tutorials no longer there.
Some of the material is rather dated, but still valid for learning x86 (32 bit) windows assembly programming.
Thanks a lot Vortex , zedd151
This is really cool
http://win32assembly.programminghorizon.com/tut3.html (http://win32assembly.programminghorizon.com/tut3.html)
Sunshine,
Have a look in the example code of MASM32 "exampl01\generic\generic.asm" for a fully commented simple window. The style is a little old dating from 1999 but it addresses the low level basics of creating a window.
hutch--
This one , right ?
; #########################################################################
;
; GENERIC.ASM is a roadmap around a standard 32 bit
; windows application skeleton written in MASM32.
;
; #########################################################################
; Assembler specific instructions for 32 bit ASM code
.386 ; minimum processor needed for 32 bit
.model flat, stdcall ; FLAT memory model & STDCALL calling
option casemap :none ; set code to case sensitive
; #########################################################################
; ---------------------------------------------
; main include file with equates and structures
; ---------------------------------------------
include \masm32\include\windows.inc
; -------------------------------------------------------------
; In MASM32, each include file created by the L2INC.EXE utility
; has a matching library file. If you need functions from a
; specific library, you use BOTH the include file and library
; file for that library.
; -------------------------------------------------------------
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
; #########################################################################
; ------------------------------------------------------------------------
; MACROS are a method of expanding text at assembly time. This allows the
; programmer a tidy and convenient way of using COMMON blocks of code with
; the capacity to use DIFFERENT parameters in each block.
; ------------------------------------------------------------------------
; 1. szText
; A macro to insert TEXT into the code section for convenient and
; more intuitive coding of functions that use byte data as text.
szText MACRO Name, Text:VARARG
LOCAL lbl
jmp lbl
Name db Text,0
lbl:
ENDM
; 2. m2m
; There is no mnemonic to copy from one memory location to another,
; this macro saves repeated coding of this process and is easier to
; read in complex code.
m2m MACRO M1, M2
push M2
pop M1
ENDM
; 3. return
; Every procedure MUST have a "ret" to return the instruction
; pointer EIP back to the next instruction after the call that
; branched to it. This macro puts a return value in eax and
; makes the "ret" instruction on one line. It is mainly used
; for clear coding in complex conditionals in large branching
; code such as the WndProc procedure.
return MACRO arg
mov eax, arg
ret
ENDM
; #########################################################################
; ----------------------------------------------------------------------
; Prototypes are used in conjunction with the MASM "invoke" syntax for
; checking the number and size of parameters passed to a procedure. This
; improves the reliability of code that is written where errors in
; parameters are caught and displayed at assembly time.
; ----------------------------------------------------------------------
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
TopXY PROTO :DWORD,:DWORD
; #########################################################################
; ------------------------------------------------------------------------
; This is the INITIALISED data section meaning that data declared here has
; an initial value. You can also use an UNINIALISED section if you need
; data of that type [ .data? ]. Note that they are different and occur in
; different sections.
; ------------------------------------------------------------------------
.data
szDisplayName db "Generic",0
CommandLine dd 0
hWnd dd 0
hInstance dd 0
; #########################################################################
; ------------------------------------------------------------------------
; This is the start of the code section where executable code begins. This
; section ending with the ExitProcess() API function call is the only
; GLOBAL section of code and it provides access to the WinMain function
; with the necessary parameters, the instance handle and the command line
; address.
; ------------------------------------------------------------------------
.code
; -----------------------------------------------------------------------
; The label "start:" is the address of the start of the code section and
; it has a matching "end start" at the end of the file. All procedures in
; this module must be written between these two.
; -----------------------------------------------------------------------
start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax ; cleanup & return to operating system
; #########################################################################
WinMain proc hInst :DWORD,
hPrevInst :DWORD,
CmdLine :DWORD,
CmdShow :DWORD
;====================
; Put LOCALs on stack
;====================
LOCAL wc :WNDCLASSEX
LOCAL msg :MSG
LOCAL Wwd :DWORD
LOCAL Wht :DWORD
LOCAL Wtx :DWORD
LOCAL Wty :DWORD
szText szClassName,"Generic_Class"
;==================================================
; Fill WNDCLASSEX structure with required variables
;==================================================
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW \
or CS_BYTEALIGNWINDOW
mov wc.lpfnWndProc, offset WndProc ; address of WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
m2m wc.hInstance, hInst ; instance handle
mov wc.hbrBackground, COLOR_BTNFACE+1 ; system color
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset szClassName ; window class name
invoke LoadIcon,hInst,500 ; icon ID ; resource icon
mov wc.hIcon, eax
invoke LoadCursor,NULL,IDC_ARROW ; system cursor
mov wc.hCursor, eax
mov wc.hIconSm, 0
invoke RegisterClassEx, ADDR wc ; register the window class
;================================
; Centre window at following size
;================================
mov Wwd, 500
mov Wht, 350
invoke GetSystemMetrics,SM_CXSCREEN ; get screen width in pixels
invoke TopXY,Wwd,eax
mov Wtx, eax
invoke GetSystemMetrics,SM_CYSCREEN ; get screen height in pixels
invoke TopXY,Wht,eax
mov Wty, eax
; ==================================
; Create the main application window
; ==================================
invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,
ADDR szClassName,
ADDR szDisplayName,
WS_OVERLAPPEDWINDOW,
Wtx,Wty,Wwd,Wht,
NULL,NULL,
hInst,NULL
mov hWnd,eax ; copy return value into handle DWORD
invoke LoadMenu,hInst,600 ; load resource menu
invoke SetMenu,hWnd,eax ; set it to main window
invoke ShowWindow,hWnd,SW_SHOWNORMAL ; display the window
invoke UpdateWindow,hWnd ; update the display
;===================================
; Loop until PostQuitMessage is sent
;===================================
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0 ; get each message
cmp eax, 0 ; exit if GetMessage()
je ExitLoop ; returns zero
invoke TranslateMessage, ADDR msg ; translate it
invoke DispatchMessage, ADDR msg ; send it to message proc
jmp StartLoop
ExitLoop:
return msg.wParam
WinMain endp
; #########################################################################
WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
; -------------------------------------------------------------------------
; Message are sent by the operating system to an application through the
; WndProc proc. Each message can have additional values associated with it
; in the two parameters, wParam & lParam. The range of additional data that
; can be passed to an application is determined by the message.
; -------------------------------------------------------------------------
.if uMsg == WM_COMMAND
;----------------------------------------------------------------------
; The WM_COMMAND message is sent by menus, buttons and toolbar buttons.
; Processing the wParam parameter of it is the method of obtaining the
; control's ID number so that the code for each operation can be
; processed. NOTE that the ID number is in the LOWORD of the wParam
; passed with the WM_COMMAND message. There may be some instances where
; an application needs to seperate the high and low words of wParam.
; ---------------------------------------------------------------------
;======== menu commands ========
.if wParam == 1000
invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
.elseif wParam == 1900
szText TheMsg,"Assembler, Pure & Simple"
invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK
.endif
;====== end menu commands ======
.elseif uMsg == WM_CREATE
; --------------------------------------------------------------------
; This message is sent to WndProc during the CreateWindowEx function
; call and is processed before it returns. This is used as a position
; to start other items such as controls. IMPORTANT, the handle for the
; CreateWindowEx call in the WinMain does not yet exist so the HANDLE
; passed to the WndProc [ hWin ] must be used here for any controls
; or child windows.
; --------------------------------------------------------------------
.elseif uMsg == WM_CLOSE
; -------------------------------------------------------------------
; This is the place where various requirements are performed before
; the application exits to the operating system such as deleting
; resources and testing if files have been saved. You have the option
; of returning ZERO if you don't wish the application to close which
; exits the WndProc procedure without passing this message to the
; default window processing done by the operating system.
; -------------------------------------------------------------------
szText TheText,"Please Confirm Exit"
invoke MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNO
.if eax == IDNO
return 0
.endif
.elseif uMsg == WM_DESTROY
; ----------------------------------------------------------------
; This message MUST be processed to cleanly exit the application.
; Calling the PostQuitMessage() function makes the GetMessage()
; function in the WinMain() main loop return ZERO which exits the
; application correctly. If this message is not processed properly
; the window disappears but the code is left in memory.
; ----------------------------------------------------------------
invoke PostQuitMessage,NULL
return 0
.endif
invoke DefWindowProc,hWin,uMsg,wParam,lParam
; --------------------------------------------------------------------
; Default window processing is done by the operating system for any
; message that is not processed by the application in the WndProc
; procedure. If the application requires other than default processing
; it executes the code when the message is trapped and returns ZERO
; to exit the WndProc procedure before the default window processing
; occurs with the call to DefWindowProc().
; --------------------------------------------------------------------
ret
WndProc endp
; ########################################################################
TopXY proc wDim:DWORD, sDim:DWORD
; ----------------------------------------------------
; This procedure calculates the top X & Y co-ordinates
; for the CreateWindowEx call in the WinMain procedure
; ----------------------------------------------------
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
; ########################################################################
end start
Thanks for the reply
Yep, that's the one. Have a look through it as it explains what the different parts of it do. Once you get this base window code, adding more to it becomes a lot easier. The basic window construction code and architecture is operating system defined so you must get it right but once you have mastered that there is a massive range of options that you can do with a basic window.
Always good to check the value of EAX after the RegisterClassEx and CreateWindowEx.
If the return value is zero, the call failed for the reason stored in EAX.
Thanks a lot for all the replies .
I wish i could code a little program that input numbers and displays the sum output inside that windows program somehow . :biggrin:
Quote from: sunshine33 on April 15, 2018, 02:46:15 PM
Thanks a lot for all the replies .
I wish i could code a little program that input numbers and displays the sum output inside that windows program somehow . :biggrin:
You also can start with simple console programs.
OK , Thanks
Hey Sunshine, that's the way to go and learn Assembly, the beast over all languages!!!!! Congrats for your initiative!
These guys are top Masm programmers that will be glad to show you the right way. Everything I learned I learned from them, you couldn't be better. Forget you reverse eng. friends, this is a lot more fun and right.
Amen to that, brother! 8)
I have only really been doing it for a week or two now, but I can vouch that these guys know their stuff and are a friendly crew to work with.
Thanks LordAdef , Lonewolff
I have a good idea now about how to make those window frames with MASM and some include files .
I am also trying to put a program together with that , that ask's for number input and display the output sum .
Quote from: Lonewolff on April 15, 2018, 02:09:47 PM
Always good to check the value of EAX after the RegisterClassEx and CreateWindowEx.
Checking the return value of RegisterClassEx will rarely help, but checking CreateWindowEx can avoid situations where your programs hangs invisibly and can only be killed with Task Manager.
QuoteIf the return value is zero, the call failed for the reason stored in EAX.
Check your logic: if eax is zero, there can be no extra information stored other than "it failed". However, you can use
print LastError$() (or Print Err$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1020) in MB) to get the reason (attention, not all WinAPI functions set or reset this value; sometimes, you see an error but the return value of eax is OK, meaning there is no error).
This much you will find with the bare mechanics of creating a window, get it right and the return values rarely ever matter. Evaluating return values when the code is correct to start with is a waste of space, just do it the right way the first time and the window will work.
Right you are.
Those two functions return zero on fail.
invoke GetLastError
This will store the actual error code in EAX.
Quote
Evaluating return values when the code is correct to start with is a waste of space, just do it the right way the first time and the window will work.
Hmmm. Yeah, but once you start experimenting with window styles, menus, etc. it is quite easy to trigger a failed call.
Once it's right, it's right. But nice to know what you are breaking when you do make something go wrong.
Can't have enough error checking, I say. Especially when you move into the realms of DirectX and not all graphics cards are created equal. What runs on one system will most certainly go bang on another.
That's where error checking and 'failing back' comes in.
To me it's a great habit to get into. Much rather being overly cautious than to have someone report that the application 'just closed' with no warning.
If any of my applications crash, it will report what went wrong (99% of the time).
Quote from: Lonewolff on April 15, 2018, 06:03:13 PMCan't have enough error checking, I say.
Right, but as Hutch wrote above, seek a balance - not every function has to be checked if the code is ok.
What you can do in any case is use macros that check for errors while testing but do not generate code when testing is over. Here is an example that I created for testing my GDI+ functions. Usage example:
invGdip GdipCreatePen1, argC$, i2f(argW$), UnitWorld, addr penName
It has three modes:
- no checking, no extra code generated
- shout foul if the function returns a value other than S_OK
- print the result to the console even if it is OK (for monitoring a sequence)
invGdip macro gpCall, args:VARARG
Local tmp$
ifidn <args>, <#>
call gpCall
else
if @InStr(1, <args>, <esp>)
tmp$ CATSTR <## line >, %@Line, <: do not use esp as gdi+ argument ##>
% echo tmp$
if usedeb
.err
endif
endif
push ecx
invoke gpCall, args
pop ecx
endif
ifndef invGdipOK
invGdipOK=0 ; >1 means show only failures
endif
if usedeb or invGdipOK
if invGdipOK eq 1
% echo gpCall args
endif
.if eax || invGdipOK eq 1
pushad
xchg eax, ecx
tmp$ CATSTR <Print "** line >, %@Line, <, &gpCall">
tmp$
PrintLine At(44, Locate(y)) Spc2$, gdiStatus$(ecx), Spc4$
popad
.endif
endif
ENDM