Looks like formatting asm code isn't liked very well. Anyway this is my two bits worth and I've enclosed the executable as a ZIP. Just rename HW.ZIP as HW.EXE and it will work fine.
Is anyone interested in modifying this app so "Hello World", shows as 3D text inside a box only when the left button is being pressed, centered around the cursor and staying inside main window.
I haven't included the windows.inc file as mine is 2300 lines long, so if you attempt to compile you'll just have to supply the required equates, or contact me and I can send you the associated INC file.
Even though this is NOT in PHP code, It does a little better job of displaying than code tags do.
[PHP] CPU P4
extern _GetMessageA@16, _TranslateMessage@4, _DispatchMessageA@4, _ExitProcess@4
extern _PostQuitMessage@4, _LoadCursorA@8, _RegisterClassExA@4, _GetModuleHandleA@4
extern _GetClientRect@8, _BeginPaint@8, _EndPaint@8, _SetBkMode@8
extern _GetStockObject@4, _InflateRect@12, _GetDC@4, _SelectObject@8
extern _TextOutA@20, _GetCommandLineA@0, _DefWindowProcA@16, _CreateWindowExA@48
TRANSPARENT EQU 1
STYLE EQU WS_SYSMENU | WS_CAPTION | WS_VISIBLE
EX_STYLE EQU WS_EX_STATICEDGE
section .bss
; ============================================================================================
MainWnd resd 1 ; Handle of main window
WndRect resd 4 ; Applications client area
section .data
;=============================================================================================
; ùùùùùùùùùùùùùùùùùùùùùù MAIN WINDOW MESSAGE MAP ùùùùùùùùùùùùùùùùùù
MWndM dw WM_DESTROY
dd Quit_Application
dw WM_CREATE
dd WndCreated
dw WM_PAINT
dd PaintWindow
MWSize equ ($ - MWndM) / 6
; ____________________________________________________________________________________________
Wc dd 48 ; cbSize
dd CS_HREDRAW | CS_VREDRAW | CS_OWNDC
dd MainWndProc ; Main window procedure
dd 0, 0 ; cbClsExtra & cbWndExtra
hInst dd 0 ; Instance Handle
dd 0 ; hIcon
dd 0 ; hCursor
dd COLOR_BTNFACE + 1
dd 0 ; Hmenu
dd AppName ; Applications name
dd 0 ; Small Icon
; ____________________________________________________________________________________________
AppTitle db 'NASM by Tight_Coder_Ex', 0
AppName db 'HW', 0
PromptStr db 'H E L L O W O R L D', 0
STRSIZE equ $ - PromptStr - 1
; ____________________________________________________________________________________________
Cw dd EX_STYLE ; dwExStyle
dd AppName ; lpClassName
dd AppTitle ; lpWindowName
dd STYLE ; dwStyle
dd CW_USEDEFAULT ; x
dd CW_USEDEFAULT ; y
dd 420 ; nWidth
dd 128 ; nHeight
dd 0 ; hWndParent
dd 0 ; hMenu
dd 0 ; hInstance
dd 0 ; lpParam
section .text
; ============================================================================================
; *** CREATE_WND ***
; ENTRY: EBX = Pointer to structure CreateWindowEx structure
; LEAVE: EAX = Handle to window, or null if failed
; CY = 0 Successful, 1 otherwise.
; --------------------------------------------------------------------------------------------
Create_Wnd mov ecx, 48
sub esp, ecx ; Create stack frame for CreateWindowEx
mov edx, esp ; Need this pointer in EDI
push esi
push edi ; Save registers
mov edi, edx
mov esi, ebx ; Setup for movsd
shr ecx, 2 ; Number of dwords to move
cld
rep movsd ; Copy parameters into stack area
pop edi
pop esi ; Restore index registers and create
call _CreateWindowExA@48 ; window
and eax, eax
jnz .Done + 1 ; If non zero, then was successful
; Error handling code will eventually go here
.Done stc ; Set error flag
ret
; ============================================================================================
; *** MESSAGE HANDLER ***
; This procedure determines if application has a handler for a particular event. All windows
; procedures are passed to this subroutine except those that have been sub or super classed.
; ENTRY: ESI = Pointer to message map
; ECX = Number of sets in map.
; Each set consists of a 16 bit ID and 32 bit pointer to proceedure.
; LEAVE: EAX = 0 if application handled event, or result of DefWindowProc is not.
; --------------------------------------------------------------------------------------------
; ESP + 0 = Return address in kernel module
; ESP + 4 = hWnd, this windows 32 bit handle
; ESP + 8 = Msg, Message ID passed by OS.
; ESP + 12 = wParam
; ESP + 16 = lParam
MsgHandler mov edx, [esp + 8] ; Get message ID 0 - 1024 or user defined.
; In the unlikely event a null map is passed to this routine, this method of
; testing ECX first will prevent a fatal crash.
.NextMsg and ecx, ecx ; Are we at the end yet
jz .Default ; ZR = 1, If we are to do default proceesing.
dec ecx ; Decrement counter
lodsw ; Get 16 bit ID from message map
cmp ax, dx ; Is there a match
lodsd ; Load pointer
jnz .NextMsg
; At this point we've found a match and as many events need wParam & lParam,
; I'm going to establish a pointer to those in EBX. hWnd can be simply addressed
; by EBX - 8 or lParam by EBX + 4.
lea ebx, [esp + 12] ; EBX points to wParam
call eax ; Execute event
jnc .Default ; CY = 0, if event requires default proc.
xor eax, eax ; Application handled need to return null.
ret 16 ; Stack needs to be re-aligned.
; As hWnd, Msg, wParam & lParam are already on the stack I use this method
; as a trace into kernel showed OS handles this appropriately and there is no
; point pushing onto stack what is already there. I've tested this on 98/ME/XP.
.Default pop ebx
call _DefWindowProcA@16
jmp ebx
; You'll notice at this point we don't need RET 16 as the call to DefWindowProc has already
; done that for us.
section .code
; ============================================================================================
; *** APPLICATION ENTRY POINT ***
; This is where application begins after OS has done its thing. I use the space before
; ShowMainWnd for anything that is not particularly related to displaying main window or is
; coded into a message handler such as WM_CREATE.
; --------------------------------------------------------------------------------------------
global Main
Main enter 28, 0 ; MSG structure in proceedure frame.
; In the event there is a failure creating main window, MSG.wParam has already been
; established. If a different value is required, set it where ever required.
lea ebx, [ebp - 28] ; EBX points to MSG
dec dword [ebx + 8] ; Msg.wParam = -1, default error condition.
call ShowMainWnd ; Display window and do other initialization.
jc .Exit ; NC = 1, Proeedure failed.
xor eax, eax ; EAX = NULL
; Applications message pump, continually scan for messages until WM_QUIT is returned.
.Pump push eax ; Save zero value in EAX
push eax ; wMsgFilterMax
push eax ; wMsgFilterMin
push eax ; hWnd = 0, Desktop
push ebx ; Pointer to MSG
call _GetMessageA@16
and eax, eax ; Evaluate returned value
jz .Exit ; ZR = 1, WM_QUIT in message que.
; If main window is a dialog box, IsDialog would be evaluated here.
push ebx
call _TranslateMessage@4
push ebx
call _DispatchMessageA@4
pop eax ; Restore NULL
jmp short .Pump
; Application has terminated, either because ShowMainWnd failed or message que
; encountered WM_QUIT. Other fatal errors usually kill app at the point they
; were encountered as ExitProcess will do appropriate cleanup anywhere.
.Exit leave
push dword [ebx + 8] ; MSG.wParam
call _ExitProcess@4 ; Cleanup
; ============================================================================================
; *** SHOW MAIN WINDOW ***
; As the name implies the only responsiblity of this section of code is to register and
; display main window.
; LEAVE: CY = 1, If either registering class or creating window failed. Additional
; code could be added to further define which caused the error.
; --------------------------------------------------------------------------------------------
ShowMainWnd push ebx
mov ebx, Wc ; Point to WNDCLASSEX structure in .data
push IDC_ARROW ; Establish main windows cursor
push byte 0
call _LoadCursorA@8
mov [ebx + 0x1c], eax ; hCursor
push byte 0
call _GetModuleHandleA@4
mov [hInst], eax
push eax
; Now that everything has been initialized the window class can be registered.
push ebx
call _RegisterClassExA@4
and eax, eax ; Set flags
jz .Exit ; EAX = 0 then registration failed.
; Create applications main window
mov ebx, Cw
pop eax
mov [ebx + 40], eax
call Create_Wnd
mov [MainWnd], eax ; Save hWnd
jnc .Exit + 1
.Exit stc
pop ebx
ret
; ============================================================================================
; Officially terminates application after user or some other method closes main window.
; --------------------------------------------------------------------------------------------
Quit_Application
push byte 0
call _PostQuitMessage@4 ; Sends quit message to window
stc ; set so no default processing
ret
align 16
; ============================================================================================
; Windows message handlers
; ENTRY: No registers are passed, windows calls this routine
; LEAVE: ESI = Points to message map
; ECX = Number of messages
; NOTE: As windows calls this procedure we want to make sure all registers except
; eax, ecx, edx are preserved.
; --------------------------------------------------------------------------------------------
MainWndProc
mov esi, MWndM ; Point to windows class structure
mov ecx, MWSize ; Number of messages in list
jmp MsgHandler
align 16
; ============================================================================================
; *** WINDOW CREATED ***
; We need these sizes everytime the right mouse button is pressed, so it might as well be done
; once here.
; --------------------------------------------------------------------------------------------
WndCreated
; Determine size of applications client area.
mov edi, WndRect
push edi
mov esi, [ebx - 8] ; hWnd
push esi
call _GetClientRect@8
; Inflate to give a 16 pixel margin around the inside. This determines the what
; could be termed the display frames clipping region.
sub eax, 17 ; Little dangerous to assume value of EAX
push eax ; just to save two bytes of code.
push eax
push edi
call _InflateRect@12
; The GetStockObject function retrieves a handle to one of the predefined stock pens,
; brushes, fonts, or palettes.
push byte DEFAULT_GUI_FONT ; System defined PEN
call _GetStockObject@4
push eax ; 2nd parameter for SelectObject call
; The GetDC function retrieves a handle to a display device context for the
; client area of a specified window or for the entire screen. You can use the
; returned handle in subsequent GDI functions to draw in the device context.
push esi
call _GetDC@4
push eax ; 1st parameter for SelectObject
; The SetBkMode function sets the background mix mode of the specified device
; context. The background mix mode is used with text, hatched brushes, and pen
; styles that are not solid lines.
push byte TRANSPARENT
push eax
call _SetBkMode@8
; The SelectObject function selects an object into the specified device context.
; The new object replaces the previous object of the same type.
call _SelectObject@8
stc
ret
; ============================================================================================
; *** PAINT EVENT ***
; The static window needs to indicate to user what he/she should do. This event looks after
; displaying that 3D message.
; --------------------------------------------------------------------------------------------
PaintWindow
enter 64, 0 ; PAINTSTRUCT
lea esi, [ebp - 64]
; BeginPaint function prepares the specified window for painting and fills a
; PAINTSTRUCT structure with information about the painting.
push esi ; PAINTSTRUCT
push dword [ebx - 8] ; hWnd
call _BeginPaint@8
push byte STRSIZE
push dword PromptStr
push byte 22
push byte 32
push eax
call _TextOutA@20
; EndPaint function marks the end of painting in the specified window.
; This function is required for each call to the BeginPaint function, but only after
; painting is complete.
push esi ; PAINTSTRUCT
push dword [ebx - 8] ; hWnd
call _EndPaint@8
leave
stc
ret
[/PHP]