Good afternoon. I'm currently building a Paint program in assembler using win32api. The functionality, as in the original Paint program, is as simple as possible: "The ability to draw with a brush, point, straight line, create a rectangle, ellipse, write text"
A problem occurred while creating shapes
Thats how my programm looks like:
Thats how problem looks like:
Code of drawing rectangle and ellipse procedure:
.elseif eax == WM_MOUSEMOVE
.if wParam == MK_LBUTTON
invoke GetCursorPos, addr CurPos
.if flag == 4
mov ecx,lParam
mov eax,lParam
shr ecx,16
and eax,0ffffh
invoke Rectangle,hdc_bitmap, CurPos.x, CurPos.y, eax, ecx
.elseif flag == 5
mov ecx,lParam
mov eax,lParam
shr ecx,16
and eax,0ffffh
invoke Ellipse,hdc_bitmap, CurPos.x, CurPos.y, eax, ecx
.endif
.endif
The rectangle is created using the Rectangle function, where we conditionally pass "canvas" as the first parameter, then the next two parameters are the x, y coordinate of the top left corner, and the last two parameters are the x, y coordinate of the bottom right corner.
As planned, when I left-click on the canvas, I should fix the coordinates of this point (and not change them later), and pass them as the coordinates of the upper left corner. To find the coordinates of the lower right corner, I use the WM_MOUSEMOVE message in which wParam will store MK_LBUTTON, and lParam will contain x, y coordinates (in the code above everything is described in more detail and clearer)
But for some reason, when I click on the canvas with the left mouse button, I create a ready-made rectangle, and when moving the mouse, the entire rectangle moves, and not its lower right corner. And in addition, when moving, the square leaves, let's say, a "trace".
Ellipse is the same story.
If someone knows how to fix this, please tell me.
All program code:
.INC file
include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc
include gdi32.inc
includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib
includelib gdi32.lib
DlgProc PROTO :HWND,:UINT,:WPARAM,:LPARAM
.const
IDD_DIALOG1 equ 101
;#########################################################################
;menu.mnu
IDR_MENU equ 10000
;----------------------------------------
IDM_File equ 10001
IDM_Open equ 10002
IDM_Save equ 10003
IDM_Close equ 10004
;----------------------------------------
IDM_Tools equ 10005
IDM_Brush equ 10006
IDM_Dot equ 10007
IDM_Line equ 10008
;----------------------------------------
IDM_Figures equ 10009
IDM_Rectangle equ 10010
IDM_Ellipse equ 10011
;----------------------------------------
IDM_Text equ 10012
;Res\SixRes.rc
MANIFEST equ 24
Paint equ 200
.data
id dd 200
hdc_bitmap dd 0
hbitmap dd 0
CurPos POINT <?>
.data?
flag dd ?
hInstance dd ?
hdc1 dd ?
;#########################################################################
.ASM file
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include Six.inc
;include RADbg.inc
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke InitCommonControls
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
invoke ExitProcess,0
;########################################################################
Draw proc
invoke BitBlt,hdc1, 0, 0, 750, 500, hdc_bitmap, 0, 0, SRCCOPY
ret
Draw endp
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
invoke LoadIcon, hInstance, id
invoke SendMessage, hWin, WM_SETICON, ICON_SMALL, eax
invoke GetDC,hWin
mov hdc1,eax
invoke CreateCompatibleDC,hdc1
mov hdc_bitmap, eax
invoke CreateCompatibleBitmap,hdc_bitmap, 750, 500
mov hbitmap, eax
invoke SelectObject, hdc_bitmap, hbitmap
invoke Rectangle, hdc_bitmap, 0, 0, 750, 500
invoke SetTimer, hWin, 12, 10, addr Draw
.elseif eax == WM_COMMAND
.if wParam == IDM_Close ; "Close"
jmp #F
.elseif wParam == IDM_Brush ; "Brush"
mov flag, 1
.elseif wParam == IDM_Dot ; "Dot"
mov flag, 2
.elseif wParam == IDM_Line ; "Line"
mov flag, 3
.elseif wParam == IDM_Rectangle ; "Rectangle"
mov flag, 4
.elseif wParam == IDM_Ellipse ; "Ellipse"
mov flag, 5
.elseif wParam == IDM_Text ; "Text"
mov flag, 6
.endif
.elseif eax == WM_MOUSEMOVE
.if wParam == MK_LBUTTON
invoke GetCursorPos, addr CurPos
.if flag == 1
mov ecx,lParam
mov eax,lParam
shr ecx,16
and eax,0ffffh
mov CurPos.y, ecx
mov CurPos.x, eax
invoke PolylineTo, hdc_bitmap, addr CurPos, 1
.elseif flag == 2
.elseif flag == 3
.elseif flag == 4
mov ecx,lParam
mov eax,lParam
shr ecx,16
and eax,0ffffh
invoke Rectangle,hdc_bitmap, CurPos.x, CurPos.y, eax, ecx
.elseif flag == 5
mov ecx,lParam
mov eax,lParam
shr ecx,16
and eax,0ffffh
invoke Ellipse,hdc_bitmap, CurPos.x, CurPos.y, eax, ecx
.elseif flag == 6
.endif
.endif
.elseif eax==WM_CLOSE
##:
invoke DeleteObject, hbitmap
invoke DeleteDC, hdc_bitmap
invoke ReleaseDC, hWin, hdc1
invoke KillTimer,hWin,12
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
end start
I tried initially to fix the coordinates of the beginning of the rectangle using the GetCursorPos function, when the left mouse button is pressed. But, for some reason, the result was not what I expected (
Related
I'm trying to recreate using MASM /w Visual Studio 2019 something similar to the following C++ code which works. Essentially at this stage just want the window to be movable and the close button to work.
#include <iostream>
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int main()
{
wchar_t windowclass[] = L"MyWinTest";
HINSTANCE hInstance = GetModuleHandleW(NULL);
MSG msg;
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = 0;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = windowclass;
wc.lpszMenuName = nullptr;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassExW(&wc);
HWND hWnd = CreateWindowExW(
0,
windowclass,
L"MyWindow",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
In my version of x64 assembly using MASM the Window is created and displayed, also WndProc is being hit, can see it get message WM_CREATE and WM_PAINT but the Window can't be moved and can't be closed. I did compile the C++ version as x64 and output assembly listing for comparison, but it looks very similar as far as I can tell to the assembly version.
WSTR MACRO lbl:req,qstr:VARARG
LOCAL arg,unq,qot,q
lbl LABEL WORD
FOR arg,<qstr>
qot SubStr <arg>,1,1
q = 0
IFIDNI qot,<!'>;'
q = 1
ELSEIFIDNI qot,<!">;"
q = 1
ELSE
DW arg
ENDIF
IF q EQ 1
unq SubStr <arg>,2,#SizeStr(<arg>)-2
% FORC c,<unq>
DW "&c"
ENDM
ENDIF
ENDM
DW 0
ENDM
L MACRO qstr:VARARG
LOCAL sym,seg
seg EQU <.code>
%IFIDNI <#CurSeg>,<_DATA>
seg EQU <.data>
ENDIF
.CONST
ALIGN 4
WSTR sym,qstr
seg
EXITM <OFFSET sym>
ENDM
extrn LoadCursorW: PROC
extrn MessageBoxW: PROC
extrn ExitProcess: PROC
extrn GetModuleHandleW: PROC
extrn RegisterClassExW: PROC
extrn CreateWindowExW: PROC
extrn GetLastError: PROC
extrn DefWindowProcW: PROC
extrn ShowWindow: PROC
extrn Sleep: PROC
extrn GetMessageW: PROC
extrn TranslateMessage: PROC
extrn DispatchMessageW: PROC
extrn DestroyWindow: PROC
extrn UpdateWindow: PROC
extrn PostQuitMessage: PROC
extrn BeginPaint: PROC
extrn EndPaint: PROC
.data
wstr windowClassName,"AsmTestClass",0,0
wstr windowTitle,"AsmTest",0,0
HWND_DESKTOP textequ <0h>
MB_OK textequ <0h>
INFINITE textequ <0ffffffffh>
WM_CREATE textequ <0001h>
WM_DESTROY textequ <0002h>
WM_SIZE textequ <0005h>
WM_PAINT textequ <000fh>
WM_CLOSE textequ <0010h>
WM_QUIT textequ <0012h>
SW_HIDE textequ <0000h>
SW_SHOW textequ <0005h>
CS_VREDRAW textequ <0001h>
CS_HREDRAW textequ <0002h>
WS_OVERLAPPED textequ <00000000h>
WS_CAPTION textequ <00c00000h>
WS_SYSMENU textequ <00080000h>
WS_MINIMIZEBOX textequ <00020000h>
CW_USEDEFAULT textequ <80000000h>
IDI_APPLICATION textequ <00007f00h>
WINDOW_WIDTH DWORD 800
WINDOW_HEIGHT DWORD 600
WNDCLASSEX STRUCT DWORD
cbSize DWORD ?
style DWORD ?
lpfnWndProc QWORD ?
cbClsExtra DWORD ?
cbWndExtra DWORD ?
hInstance QWORD ?
hIcon QWORD ?
hCursor QWORD ?
hbrBackground QWORD ?
lpszMenuName QWORD ?
lpszClassName QWORD ?
hIconSm QWORD ?
WNDCLASSEX ENDS
MSG STRUCT
hwnd QWORD ?
message DWORD ?
wParam QWORD ?
lParam QWORD ?
time DWORD ?
x DWORD ?
y DWORD ?
MSG ENDS
PAINTSTRUCT STRUCT 8
hdc QWORD ?
fErase DWORD ?
left DWORD ?
top DWORD ?
right DWORD ?
bottom DWORD ?
fRestore DWORD ?
fIncUpdate DWORD ?
rgbReserved BYTE 32 DUP (?)
PAINTSTRUCT ENDS
.code
main proc
LOCAL wc:WNDCLASSEX
LOCAL hWnd:QWORD
LOCAL hInstance:QWORD
LOCAL hCursor:QWORD
LOCAL ATOM:WORD
LOCAL message:MSG
sub rsp, 8
; hInstance = GetModuleHandle(NULL)
mov rcx, 0
call GetModuleHandleW
mov hInstance, rax
; hCursor = LoadCursor(NULL,IDI_APPLICATION)
mov edx, IDI_APPLICATION
xor ecx, ecx
call LoadCursorW
mov hCursor, rax
; Setup Window Class
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_VREDRAW or CS_HREDRAW
lea rax, OFFSET WndProc
mov wc.lpfnWndProc, rax
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
lea rax, hInstance
mov wc.hInstance, rax
mov wc.hbrBackground, 0
mov wc.lpszMenuName, 0
lea rax, hCursor
mov wc.hCursor, rax
lea rax, windowClassName
mov wc.lpszClassName, rax
mov wc.hIconSm, 0
lea rcx, wc
call RegisterClassExW
mov ATOM, ax
; CreateWindowExW
mov QWORD PTR [rsp+88], 0 ; lpParam
lea rax, hInstance
mov QWORD PTR [rsp+80], rax ; hInstance
mov QWORD PTR [rsp+72], 0 ; hMenu
mov QWORD PTR [rsp+64], 0 ; hWndParent
mov edx, WINDOW_HEIGHT
mov DWORD PTR [rsp+56], edx ; nHeight
mov edx, WINDOW_WIDTH
mov DWORD PTR [rsp+48], edx ; nWidth
mov DWORD PTR [rsp+40], CW_USEDEFAULT ; Y
mov DWORD PTR [rsp+32], CW_USEDEFAULT ; X
mov r9d, WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX ; dwStyle
lea r8, windowTitle ; lpWindowName
lea rdx, windowClassName ; lpClassName
xor ecx,ecx ; dwExStyle
call CreateWindowExW
cmp rax, 0
je WindowFailed
jmp WindowSuccess
WindowFailed:
call GetLastError
; to-do check error ?
WindowSuccess:
mov hWnd, rax
mov rcx, hWnd ; hWnd
mov edx, SW_SHOW ; nCmdShow
call ShowWindow
mov rcx, hWnd ; hWnd
call UpdateWindow
MessageLoop:
xor r9d, r9d ; wMsgFilterMax
xor r8d, r8d ; wMsgFilterMin
xor edx, edx ; hWnd
lea rcx, message ; lpMsg
call GetMessageW
test eax, eax
je QuitMessageLoop
lea rcx, message ; lpMsg
call TranslateMessage
lea rcx, message ; lpMsg
call DispatchMessageW
jmp MessageLoop
QuitMessageLoop:
mov ecx, eax ; uExitCode
call ExitProcess
main endp
WndProc proc
LOCAL hWnd:QWORD
LOCAL uMsg:DWORD
LOCAL wParam:QWORD
LOCAL lParam:QWORD
LOCAL result:QWORD
LOCAL ps:PAINTSTRUCT
LOCAL hdc:QWORD
sub rsp, 8
mov lParam, r9
mov wParam, r8
mov uMsg, edx
mov hWnd, rcx
; msg handler
cmp uMsg,WM_CREATE
je create
cmp uMsg,WM_PAINT
je paint
cmp uMsg,WM_DESTROY
je destroy
; default
mov r9, lParam
mov r8, wParam
mov edx, uMsg
mov rcx, hWnd
call DefWindowProcW
mov result,rax
jmp finish
create:
mov result, 0
jmp finish
paint:
mov rcx, hWnd
lea rdx, ps
call BeginPaint
mov hdc, rax
; to-do HDC paint stuff here
mov rcx, hWnd
lea rdx, ps
call EndPaint
mov result, 0
jmp finish
destroy:
xor ecx, ecx ; nExitCode
call PostQuitMessage
mov result, 0
jmp finish
finish:
mov rax, result
ret
WndProc endp
End
Note due to local statement masm is automatically adding to my main before the sub rsp,8: (-152 + -8 = -160 )
push rbp
mov rbp, rsp
add rsp, 0FFFFFFFFFFFFFF68h
and adding to wndproc routine (-120 + -8 = -128)
push rbp
mov rbp, rsp
add rsp, 0FFFFFFFFFFFFFF88h
...
leave
error in code - in both procs -
sub rsp, 8
when from x64 calling convention
The caller is responsible for allocating space for the callee's parameters. The caller must always allocate sufficient space to store
four register parameters, even if the callee doesn't take that many
parameters.
so need - to store four register parameters - 4*8 and +8 for 16-byte align, so
sub rsp, 40
in concrete case calls to DispatchMessageW and TranslateMessage can corrupt (overwrite) message because it located in callee's parameters space. if test under debugger - i view that DispatchMessageW overwrite message in prolog and than already use wrong message
I have a simple fasm program, in this program I get some zeroed memory from windows through VirtualAlloc. I then have a procedure where I simply set up the parameters and make a call to StretchDIBits passing a pointer to the empty memory buffer. I therefore expect the screen should be drawn black. This however is not the case, and I can't for the life of me figure out why.
Below is the code.
format PE64 GUI
entry main
include 'C:\Users\bmowo\Desktop\Tools\fasm\INCLUDE\win64a.inc'
include '.\main_data.asm'
section '.text' code readable executable
main:
sub rsp,8 ;alignment
invoke GetModuleHandle,0
mov [WindowClass.hInstance], rax
invoke LoadIcon,0,IDI_APPLICATION
mov [WindowClass.hIcon],rax
mov [WindowClass.hIconSm],rax
invoke LoadCursor,0,IDC_ARROW
mov [WindowClass.hCursor],rax
mov rax, CS_OWNDC or CS_HREDRAW or CS_VREDRAW
mov [WindowClass.style], eax
invoke RegisterClassExA,WindowClass
test rax, rax
jz exit
invoke CreateWindowExA,0,WindowClassName,WindowTitle, WS_VISIBLE+WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0,0,[WindowClass.hInstance],0
mov [WindowHandle], rax
test rax, rax
jz exit
mov rax, 2*gigabyte
mov r10d, MEM_COMMIT or MEM_RESERVE
invoke VirtualAlloc,0,eax,r10d,PAGE_READWRITE
mov [Memory], rax
mov [GlobalRunning], 1
.main_loop:
cmp [GlobalRunning], 0
je exit
stdcall Win32MessagePump
jmp .main_loop
exit:
invoke ExitProcess,[Message.wParam]
proc BlitBuffer
locals
Width dd 0
Height dd 0
PixelsBase dq 0
DC dq 0
BitmapInfo BITMAPINFO 0
ScreenRect RECT
endl
;get window region
lea rax, [ScreenRect]
invoke GetClientRect, [WindowHandle], rax
;calculate width and height
mov ecx, [ScreenRect.bottom]
sub ecx, [ScreenRect.top]
mov [Height], ecx
mov ecx, [ScreenRect.left]
sub ecx, [ScreenRect.right]
mov [Width], ecx
BitmapInfoHeaderSize equ 40
BI_RGB equ 0
mov [BitmapInfo.biSize], BitmapInfoHeaderSize ;sizeof bitmapinfoheader is 40
mov eax, [Width]
mov [BitmapInfo.biWidth], eax
mov eax, [Height]
mov [BitmapInfo.biHeight], eax
mov [BitmapInfo.biPlanes], 1
mov [BitmapInfo.biBitCount], 32
mov [BitmapInfo.biCompression], BI_RGB
mov [BitmapInfo.biSizeImage], 0
mov [BitmapInfo.biXPelsPerMeter], 0
mov [BitmapInfo.biYPelsPerMeter], 0
mov [BitmapInfo.biClrUsed], 0
mov [BitmapInfo.biClrImportant], 0
mov [BitmapInfo.RGBQUADa], 0
mov [BitmapInfo.RGBQUADb], 0
mov [BitmapInfo.RGBQUADc], 0
mov [BitmapInfo.RGBQUADd], 0
mov rax, [Memory]
mov [PixelsBase], rax
invoke GetDC, [WindowHandle]
mov [DC], rax
lea rax, [BitmapInfo]
DIB_RGB_COLORS equ 0
invoke StretchDIBits, [DC],0,0,[Width],[Height],0,0,[Width],[Height],[PixelsBase], rax,DIB_RGB_COLORS,SRCCOPY
ret
endp
proc Win32ToggleWindowFullScreen
locals
WindowStyle dd 0
MonitorInfo MONITORINFO sizeof.MONITORINFO
endl
GWL_STYLE equ -16
SWP_NOOWNERZORDER equ 0x0200
SWP_FRAMECHANGED equ 0x0020
SWP_NOMOVE equ 0x0002
SWP_NOSIZE equ 0x0001
SWP_NOZORDER equ 0x0004
HWND_TOP equ 0
SWP_FRAMECHANGED equ 0x0020
WS_OVERLAPPEDWINDOW equ 0xcf0000
MONITOR_DEFAULTTOPRIMARY equ 1
invoke GetWindowLongA, [WindowHandle], GWL_STYLE
mov [WindowStyle], eax
mov rbx, WS_OVERLAPPEDWINDOW
and eax, ebx
jz .else
invoke GetWindowPlacement, [WindowHandle], GlobalWindowPlacement
mov r8, rax
cmp rax, 1
jb .end
invoke MonitorFromWindow,[WindowHandle], MONITOR_DEFAULTTOPRIMARY
lea rbx, [MonitorInfo]
invoke GetMonitorInfoA,rax,rbx
cmp rax, 1
jb .end
mov rbx, not WS_OVERLAPPEDWINDOW ;not rbx
mov eax, [WindowStyle]
and eax, ebx
invoke SetWindowLongA, [WindowHandle], GWL_STYLE, eax
mov eax, [MonitorInfo.rcMonitor.right]
sub eax, [MonitorInfo.rcMonitor.left]
mov r10d, [MonitorInfo.rcMonitor.bottom]
sub r10d, [MonitorInfo.rcMonitor.top]
mov r11, HWND_TOP or SWP_NOOWNERZORDER or SWP_FRAMECHANGED
invoke SetWindowPos, [WindowHandle],0,[MonitorInfo.rcMonitor.left],[MonitorInfo.rcMonitor.top],eax,r10d,r11d
jmp .end
.else:
mov eax, [WindowStyle]
or rax, WS_OVERLAPPEDWINDOW
invoke SetWindowLongA, [WindowHandle],GWL_STYLE,eax
invoke SetWindowPlacement,[WindowHandle],GlobalWindowPlacement
mov rax, SWP_NOOWNERZORDER or SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER
invoke SetWindowPos,[WindowHandle],0,0,0,0,0,eax
.end:
ret
endp
proc Win32MessagePump
.while_message:
invoke PeekMessageA,Message,[WindowHandle],0,0,PM_REMOVE
cmp eax, 0
je .end
cmp [Message.message], WM_KEYDOWN
je .keydown
cmp [Message.message], WM_PAINT
je .paint
.default:
invoke TranslateMessage,Message
invoke DispatchMessage,Message
jmp .while_message
.keydown:
stdcall Win32ToggleWindowFullScreen
.paint:
invoke BeginPaint,[WindowHandle],PaintStruct
stdcall BlitBuffer
invoke EndPaint,[WindowHandle],PaintStruct
jmp .while_message
.end:
ret
endp
proc Win32CallbackProc ;hwnd,wmsg,wparam,lparam
cmp edx, WM_DESTROY
je .close
cmp edx, WM_CLOSE
je .close
cmp edx, WM_QUIT
je .close
.default:
invoke DefWindowProcA,rcx,rdx,r8,r9
jmp .end
.close:
mov [GlobalRunning], 0
jmp .end
.end:
ret
endp
'''
GlobalWindowPlacement WINDOWPLACEMENT sizeof.WINDOWPLACEMENT
breakit equ int3
kilobyte equ 1024
megabyte equ 1024*1024
gigabyte equ 1024*1024*1024
struct BITMAPINFO
biSize dd ?
biWidth dd ?
biHeight dd ?
biPlanes dw ?
biBitCount dw ?
biSizeImage dd 0
biXPelsPerMeter dd 0
biYPelsPerMeter dd 0
biClrUsed dd 0
biClrImportant dd 0
RGBQUADa db 0
RGBQUADb db 0
RGBQUADc db 0
RGBQUADd db 0
ends
PaintStruct PAINTSTRUCT
struct MONITORINFO
cbSize dd ?
rcMonitor RECT ?
rcWork RECT ?
dwFlags dd ?
ends
section '.data' data readable writeable
GlobalRunning db 0
WindowClassName db "fasm app",0
WindowTitle db "Raytracer or Rasteriser or somethin",0
;WindowClass WNDCLASSEX sizeof.WNDCLASSEX,0,Win32CallbackProc,0,0,0,0,0,COLOR_WINDOW,0,WindowClassName,0
WindowClass WNDCLASSEX sizeof.WNDCLASSEX,0,Win32CallbackProc,0,0,0,0,0,0,0,WindowClassName,0
Message MSG
WindowHandle dq 0
WindowDC dq 0
Memory dq 0
section '.idata' import data readable writeable
library kernel,'kernel32.dll',\
user,'user32.dll',\
gdi, 'gdi32.dll'
import kernel,\
GetModuleHandle,'GetModuleHandleA',\
ExitProcess,'ExitProcess',\
VirtualAlloc, 'VirtualAlloc',\
VirtualFree, 'VirtualFree',\
GetLastError, 'GetLastError',\
SetLastError, 'SetLastError'\
import user,\
RegisterClassExA,'RegisterClassExA',\
CreateWindowExA,'CreateWindowExA',\
ShowWindow,'ShowWindow',\
UpdateWindow,'UpdateWindow',\
DefWindowProcA,'DefWindowProcA',\
GetMessage,'GetMessageA',\
TranslateMessage,'TranslateMessage',\
DispatchMessage,'DispatchMessageA',\
LoadCursor,'LoadCursorA',\
LoadIcon,'LoadIconA',\
GetClientRect,'GetClientRect',\
GetDC,'GetDC',\
ReleaseDC,'ReleaseDC',\
BeginPaint,'BeginPaint',\
EndPaint,'EndPaint',\
PostQuitMessage,'PostQuitMessage',\
MessageBoxA, 'MessageBoxA',\
PeekMessageA, 'PeekMessageA',\
GetWindowLongA, 'GetWindowLongA',\
GetWindowPlacement,'GetWindowPlacement',\
SetWindowPlacement, 'SetWindowPlacement',\
GetMonitorInfoA, 'GetMonitorInfoA',\
SetWindowLongA, 'SetWindowLongA',\
SetWindowPos, 'SetWindowPos',\
MonitorFromWindow, 'MonitorFromWindow'
import gdi,\
StretchDIBits, 'StretchDIBits',\
PatBlt, 'PatBlt'
conclusion. It's been pointed out to me that the invoke macro is clobbering the rax register which I was using for [BitmapInfo] so that was dumb. Fixing that issue results in the expected black screen.
Invoke macro is clobbering the parameter being passed through rax.
I'm sorry I don't know much about fasm, I tried to reproduce the problem through C++:
void* p = VirtualAlloc(NULL, 512 * 512, MEM_COMMIT, PAGE_READWRITE);
BITMAPINFO bi{};
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = 512;
bi.bmiHeader.biHeight = 512;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
StretchDIBits(hdc, 0, 0, 512, 512, 0, 0, 512, 512, p, &bi, DIB_RGB_COLORS, SRCCOPY);
I tried to use the above code and reproduced the problem. Under my test, I think the allocated memory space is not enough.
I modified it to:
void* p = VirtualAlloc(NULL, 512 * 512 * 4, MEM_COMMIT, PAGE_READWRITE);
Then it works for me.
I am currently trying to learn how to use FASM and I've been trying to make an application that draws colored lines using only WinAPI and GDI, but I can't figure out how to do that. I found this template for drawing lines, but they are always black.
format PE GUI 4.0
include 'win32wx.inc'
.data
_class TCHAR 'FASMWIN32',0
_title TCHAR 'Win32 program template',0
_error TCHAR 'Startup failed.',0
wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BACKGROUND,NULL,_class
msg MSG
hdc dd ?
paintstruct PAINTSTRUCT
.code
start:
invoke GetModuleHandle,0
mov [wc.hInstance],eax
invoke LoadIcon,0,IDI_APPLICATION
mov [wc.hIcon],eax
invoke LoadCursor,0,IDC_ARROW
mov [wc.hCursor],eax
invoke CreateSolidBrush, 0xFFFFFF
mov [wc.hbrBackground], eax
invoke RegisterClass,wc
test eax,eax
jz error
invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,128,128,256,192,NULL,NULL,[wc.hInstance],NULL
test eax,eax
jz error
msg_loop:
invoke GetMessage,msg,NULL,0,0
cmp eax,1
jb end_loop
jne msg_loop
invoke TranslateMessage,msg
invoke DispatchMessage,msg
jmp msg_loop
error:
invoke MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop:
invoke ExitProcess,[msg.wParam]
proc WindowProc uses ebx esi edi, hwnd,wmsg,wparam,lparam
cmp [wmsg], WM_DESTROY
je .wmdestroy
cmp [wmsg], WM_PAINT
je .wmpaint
.defwndproc:
invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
jmp .finish
.wmdestroy:
invoke PostQuitMessage,0
xor eax,eax
jmp .finish
.wmpaint:
invoke BeginPaint, [hwnd], paintstruct
mov [hdc], eax
invoke MoveToEx, [hdc], 10, 15, 0
invoke LineTo, [hdc], 200, 100
invoke EndPaint, [hwnd], paintstruct
.finish:
ret
endp
.end start
This doesn't seem to work either, unless I am trying to put "hBrush HBRUSH" in the wrong place (doesn't work in '.data', 'illegal instruction'; "HBRUSH hBrush" doesn't work as well).
hBrush HBRUSH
invoke CreateSolidBrush, 0xFFFFFF
invoke SelectObject [hdc], hBrush
Can someone please give me an example of drawing colored lines with WinAPI and GDI?
My mistake was that I was trying to use brushes instead of pens to draw lines. If someone has the same question, the code is:
invoke CreatePen,PS_SOLID, 1, 0x000000 ; PS_SOLID is the pen style and 0x000000 is the color
invoke SelectObject, [hdc], eax
invoke MoveToEx, [hdc], 0, 32, 0
invoke LineTo, [hdc], 256, 32
Full example:
format PE GUI 4.0
include 'win32wx.inc'
.data
_class TCHAR 'FASMWIN32',0
_title TCHAR 'Win32 program template',0
_error TCHAR 'Startup failed.',0
wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BACKGROUND,NULL,_class
msg MSG
hdc dd ?
paintstruct PAINTSTRUCT
.code
start:
invoke GetModuleHandle,0
mov [wc.hInstance],eax
invoke LoadIcon,0,IDI_APPLICATION
mov [wc.hIcon],eax
invoke LoadCursor,0,IDC_ARROW
mov [wc.hCursor],eax
invoke CreateSolidBrush, 0xA0A0A0
mov [wc.hbrBackground], eax
invoke RegisterClass,wc
test eax,eax
jz error
invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_OVERLAPPEDWINDOW,128,128,256,192,NULL,NULL,[wc.hInstance],NULL
test eax,eax
jz error
msg_loop:
invoke GetMessage,msg,NULL,0,0
cmp eax,1
jb end_loop
jne msg_loop
invoke TranslateMessage,msg
invoke DispatchMessage,msg
jmp msg_loop
error:
invoke MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
end_loop:
invoke ExitProcess,[msg.wParam]
proc WindowProc uses ebx esi edi, hwnd,wmsg,wparam,lparam
cmp [wmsg], WM_DESTROY
je .wmdestroy
cmp [wmsg], WM_PAINT
je .wmpaint
.defwndproc:
invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
jmp .finish
.wmdestroy:
invoke PostQuitMessage,0
xor eax,eax
jmp .finish
.wmpaint:
invoke BeginPaint, [hwnd], paintstruct
mov [hdc], eax
invoke CreatePen,PS_SOLID, 1, 0x000000
invoke SelectObject, [hdc], eax
invoke MoveToEx, [hdc], 0, 32, 0
invoke LineTo, [hdc], 256, 32
invoke EndPaint, [hwnd], paintstruct
.finish:
ret
endp
.end start
I'm creating simple game using Win32 API. When I click on window, a ball appear and start rolling look like bida game
My problem is when I call "InvalidateRect", my game very lag. I don't know I'm doing any thing wrong!!!
And my hPen didn't work like what I expect
Please help!!!
Thank you and sorry for my bad English
.386 ; use 80386 instruction
.model flat,stdcall ; uses flat memory addressing model
option casemap:none
include C:\masm32\include\windows.inc ; windows.inc have structures and constants
include C:\masm32\include\user32.inc
includelib C:\masm32\lib\user32.lib ; CreateWindowEx, RegisterClassEx,...
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib ; ExitProcess
include C:\masm32\include\masm32.inc
includelib C:\masm32\lib\masm32.lib
include C:\masm32\include\gdi32.inc
includelib C:\masm32\lib\gdi32.lib
.CONST
DRAWING equ 1
WAITING equ 0
PEN_COLOR equ 00000000h ; black
PEN_SIZE equ 2
BALL_SIZE equ 35
BALL_SPEED equ 20
.DATA
ClassName db 'SimpleWinClass',0
AppName db 'Ball',0
state db WAITING
vectorX dd 6
vectorY dd -7
WIN_WIDTH dd 700
WIN_HEIGHT dd 500
.DATA?
; HINSTANCE & LPSTR typedef DWORD in windows.inc
; reserve the space for future use
hInstance HINSTANCE ?
tlpoint POINT <>
brpoint POINT <>
; use for create window
wc WNDCLASSEX <?>
msg MSG <?> ; handle message
hwnd HWND ? ; handle window procedure
hdc HDC ?
ps PAINTSTRUCT <?>
time SYSTEMTIME <?>
hPen HPEN ?
.CODE
start:
; call GetModuleHandle(null)
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683199(v=vs.85).aspx
push NULL
call GetModuleHandle ; module handle same as instance handle in Win32
mov hInstance, eax ; return an instance to handle in eax
; call WinMain(hInstance, hPrevInstance, CmdLine, CmdShow)
; our main function
push SW_SHOW
push NULL
push NULL
push hInstance
call WinMain
; call ExitProcess
push eax
call ExitProcess
; Define WinMain
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
; Structure in msdn, define in windows.inc
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx
; Load default icon
push IDI_APPLICATION
push NULL
call LoadIcon
mov wc.hIcon, eax
mov wc.hIconSm, eax
; Load default cursor
push IDC_ARROW
push NULL
call LoadCursor
mov wc.hCursor, eax
mov wc.cbSize, SIZEOF WNDCLASSEX ; size of this structure
mov wc.style, CS_HREDRAW or CS_VREDRAW ; style of windows https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx
mov wc.lpfnWndProc, OFFSET WndProc ; andress of window procedure
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW+1 ; background color, require to add 1
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, OFFSET ClassName
; we register our own class, named in ClassName
push offset wc
call RegisterClassEx
; after register ClassName, we use it to create windows compond
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
push NULL
push hInstance
push NULL
push NULL
push WIN_HEIGHT
push WIN_WIDTH
push CW_USEDEFAULT
push CW_USEDEFAULT
push WS_OVERLAPPEDWINDOW
push offset AppName
push offset ClassName
push WS_EX_CLIENTEDGE
call CreateWindowEx
mov hwnd, eax ; return windows handle
; display window
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
push CmdShow
push hwnd
call ShowWindow
; update window
; https://msdn.microsoft.com/en-us/library/windows/desktop/dd145167(v=vs.85).aspx
push hwnd
call UpdateWindow
; Message Loop
MESSAGE_LOOP:
; get message
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
push PM_REMOVE
push 0
push 0
push NULL
push offset msg
call PeekMessage
; return in eax
; if the function retrieves a message other than WM_QUIT, the return value is nonzero.
; if the function retrieves the WM_QUIT message, the return value is zero.
cmp eax, 0
je GAME_LOOP
cmp msg.message, WM_QUIT
je END_LOOP
; translate virtual-key messages into character messages - ASCII in WM_CHAR
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644955(v=vs.85).aspx
push offset msg
call TranslateMessage
; sends the message data to the window procedure responsible for the specific window the message is for.
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644934(v=vs.85).aspx
push offset msg
call DispatchMessage
GAME_LOOP:
; check that is DRAWING or not?
cmp [state], DRAWING
jne MESSAGE_LOOP
push offset time
call GetSystemTime
cmp dword ptr[time.wMilliseconds], BALL_SPEED
jl MESSAGE_LOOP
push TRUE
push NULL
push hwnd
call InvalidateRect
jmp MESSAGE_LOOP
END_LOOP:
mov eax, msg.wParam
ret
WinMain endp
; Handle message with switch(notification)
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
cmp uMsg, WM_PAINT
je ON_WM_PAINT
cmp uMsg, WM_CREATE
je ON_WM_CREATE
cmp uMsg, WM_LBUTTONDOWN
je ON_WM_LBUTTONDOWN
cmp uMsg, WM_DESTROY
je ON_WM_DESTROY
cmp uMsg, WM_QUIT
je ON_WM_DESTROY
cmp uMsg, WM_CLOSE
je ON_WM_DESTROY
jmp ON_DEFAULT
; user close program
ON_WM_DESTROY:
push NULL
call PostQuitMessage
jmp EXIT
ON_WM_CREATE:
; create a pen with specific color and size
; https://msdn.microsoft.com/en-us/library/windows/desktop/dd183509(v=vs.85).aspx
push PEN_COLOR
push PEN_SIZE
push PS_SOLID
call CreatePen
mov hPen, eax
jmp EXIT
ON_WM_LBUTTONDOWN:
cmp [state], DRAWING
je EXIT
push lParam
call updateXY
; when clicked, set state to DRAWING
mov [state], DRAWING
mov dword ptr[time.wMilliseconds], BALL_SPEED
push offset time
call SetSystemTime
jmp EXIT
ON_WM_PAINT:
mov dword ptr[time.wMilliseconds], 0
push offset time
call SetSystemTime
push offset ps
push hWnd
call BeginPaint
mov hdc, eax
; apply pen to hdc
push hPen
push hdc
call SelectObject
call createEllipse
push offset ps
push hWnd
call EndPaint
jmp EXIT
ON_DEFAULT:
; handle any message that program don't handle
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633572(v=vs.85).aspx
push lParam
push wParam
push uMsg ; message
push hWnd ; windows
call DefWindowProc
jmp EXIT
EXIT:
ret
WndProc endp
createEllipse proc
push brpoint.y
push brpoint.x
push tlpoint.y
push tlpoint.x
push hdc
call Ellipse
call moveEllipse
mov eax, WIN_WIDTH
cmp brpoint.x, eax
jg MEET_RIGHT_LEFT
mov eax, WIN_HEIGHT
cmp brpoint.y, eax
jg MEET_BOTTOM_TOP
cmp tlpoint.x, 0
jl MEET_RIGHT_LEFT
cmp tlpoint.y, 0
jl MEET_BOTTOM_TOP
jmp MEET_NONE
MEET_RIGHT_LEFT:
neg vectorX
jmp MEET_NONE
MEET_BOTTOM_TOP:
neg vectorY
jmp MEET_NONE
MEET_NONE:
ret
createEllipse endp
moveEllipse proc
mov eax, dword ptr[vectorX]
mov ecx, dword ptr[vectorY]
add tlpoint.x, eax
add tlpoint.y, ecx
add brpoint.x, eax
add brpoint.y, ecx
ret
moveEllipse endp
updateXY proc lParam:LPARAM
mov eax, lParam
; get low word that contain x
xor ebx, ebx
mov bx, ax
mov tlpoint.x, ebx
mov brpoint.x, ebx
add brpoint.x, BALL_SIZE
; get high word that contain y
mov eax, lParam
shr eax, 16
mov tlpoint.y, eax
mov brpoint.y, eax
add brpoint.y, BALL_SIZE
ret
updateXY endp
end start
It's not a good idea to use the system time for speed issues. Use your procedure moveEllipse instead and increase vectorX and vectorY for more speed. InvalidateRec should be called if there is a real update needed. You can reach that by using a timer instead of changing and checking the system time: SetTimer.
.386 ; use 80386 instruction
.model flat,stdcall ; uses flat memory addressing model
option casemap:none
include C:\masm32\include\windows.inc ; windows.inc have structures and constants
include C:\masm32\include\user32.inc
includelib C:\masm32\lib\user32.lib ; CreateWindowEx, RegisterClassEx,...
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib ; ExitProcess
include C:\masm32\include\masm32.inc
includelib C:\masm32\lib\masm32.lib
include C:\masm32\include\gdi32.inc
includelib C:\masm32\lib\gdi32.lib
.CONST
DRAWING equ 1
WAITING equ 0
PEN_COLOR equ 00000000h ; black
PEN_SIZE equ 2
BALL_SIZE equ 35
BALL_SPEED equ 20
.DATA
ClassName db 'SimpleWinClass',0
AppName db 'Ball',0
state db WAITING
vectorX dd 19
vectorY dd -19
WIN_WIDTH dd 700
WIN_HEIGHT dd 500
.DATA?
; HINSTANCE & LPSTR typedef DWORD in windows.inc
; reserve the space for future use
hInstance HINSTANCE ?
tlpoint POINT <>
brpoint POINT <>
; use for create window
wc WNDCLASSEX <?>
msg MSG <?> ; handle message
hwnd HWND ? ; handle window procedure
hdc HDC ?
ps PAINTSTRUCT <?>
time SYSTEMTIME <?>
hPen HPEN ?
.CODE
start:
; call GetModuleHandle(null)
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683199(v=vs.85).aspx
push NULL
call GetModuleHandle ; module handle same as instance handle in Win32
mov hInstance, eax ; return an instance to handle in eax
; call WinMain(hInstance, hPrevInstance, CmdLine, CmdShow)
; our main function
push SW_SHOW
push NULL
push NULL
push hInstance
call WinMain
; call ExitProcess
push eax
call ExitProcess
; Define WinMain
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
; Structure in msdn, define in windows.inc
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx
; Load default icon
push IDI_APPLICATION
push NULL
call LoadIcon
mov wc.hIcon, eax
mov wc.hIconSm, eax
; Load default cursor
push IDC_ARROW
push NULL
call LoadCursor
mov wc.hCursor, eax
mov wc.cbSize, SIZEOF WNDCLASSEX ; size of this structure
mov wc.style, CS_HREDRAW or CS_VREDRAW ; style of windows https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx
mov wc.lpfnWndProc, OFFSET WndProc ; andress of window procedure
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW+1 ; background color, require to add 1
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, OFFSET ClassName
; we register our own class, named in ClassName
push offset wc
call RegisterClassEx
; after register ClassName, we use it to create windows compond
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
push NULL
push hInstance
push NULL
push NULL
push WIN_HEIGHT
push WIN_WIDTH
push CW_USEDEFAULT
push CW_USEDEFAULT
push WS_OVERLAPPEDWINDOW
push offset AppName
push offset ClassName
push WS_EX_CLIENTEDGE
call CreateWindowEx
mov hwnd, eax ; return windows handle
; display window
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
push CmdShow
push hwnd
call ShowWindow
; update window
; https://msdn.microsoft.com/en-us/library/windows/desktop/dd145167(v=vs.85).aspx
push hwnd
call UpdateWindow
; Message Loop
MESSAGE_LOOP:
; get message
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
push 0
push 0
push NULL
push offset msg
call GetMessage
; return in eax
; if the function retrieves a message other than WM_QUIT, the return value is nonzero.
; if the function retrieves the WM_QUIT message, the return value is zero.
test eax, eax
jle END_LOOP
; translate virtual-key messages into character messages - ASCII in WM_CHAR
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644955(v=vs.85).aspx
push offset msg
call TranslateMessage
; sends the message data to the window procedure responsible for the specific window the message is for.
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644934(v=vs.85).aspx
push offset msg
call DispatchMessage
jmp MESSAGE_LOOP
END_LOOP:
mov eax, msg.wParam
ret
WinMain endp
TimerProc PROC thwnd:HWND, uMsg:UINT, idEvent:UINT, dwTime:DWORD
push TRUE
push NULL
push thwnd
call InvalidateRect
ret
TimerProc ENDP
; Handle message with switch(notification)
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
cmp uMsg, WM_PAINT
je ON_WM_PAINT
cmp uMsg, WM_CREATE
je ON_WM_CREATE
cmp uMsg, WM_LBUTTONDOWN
je ON_WM_LBUTTONDOWN
cmp uMsg, WM_DESTROY
je ON_WM_DESTROY
cmp uMsg, WM_QUIT
je ON_WM_DESTROY
cmp uMsg, WM_CLOSE
je ON_WM_DESTROY
jmp ON_DEFAULT
; user close program
ON_WM_DESTROY:
push NULL
call PostQuitMessage
jmp EXIT
ON_WM_CREATE:
; create a pen with specific color and size
; https://msdn.microsoft.com/en-us/library/windows/desktop/dd183509(v=vs.85).aspx
push PEN_COLOR
push PEN_SIZE
push PS_SOLID
call CreatePen
mov hPen, eax
jmp EXIT
ON_WM_LBUTTONDOWN:
cmp [state], DRAWING
je EXIT
push lParam
call updateXY
; when clicked, set state to DRAWING
mov [state], DRAWING
push OFFSET TimerProc
push 20
push 1
push hwnd
call SetTimer
; mov dword ptr[time.wMilliseconds], BALL_SPEED
; push offset time
; call SetSystemTime
jmp EXIT
ON_WM_PAINT:
mov dword ptr[time.wMilliseconds], 0
push offset ps
push hWnd
call BeginPaint
mov hdc, eax
; apply pen to hdc
push hPen
push hdc
call SelectObject
call createEllipse
push offset ps
push hWnd
call EndPaint
jmp EXIT
ON_DEFAULT:
; handle any message that program don't handle
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633572(v=vs.85).aspx
push lParam
push wParam
push uMsg ; message
push hWnd ; windows
call DefWindowProc
jmp EXIT
EXIT:
ret
WndProc endp
createEllipse proc
push brpoint.y
push brpoint.x
push tlpoint.y
push tlpoint.x
push hdc
call Ellipse
call moveEllipse
mov eax, WIN_WIDTH
cmp brpoint.x, eax
jg MEET_RIGHT_LEFT
mov eax, WIN_HEIGHT
cmp brpoint.y, eax
jg MEET_BOTTOM_TOP
cmp tlpoint.x, 0
jl MEET_RIGHT_LEFT
cmp tlpoint.y, 0
jl MEET_BOTTOM_TOP
jmp MEET_NONE
MEET_RIGHT_LEFT:
neg vectorX
jmp MEET_NONE
MEET_BOTTOM_TOP:
neg vectorY
jmp MEET_NONE
MEET_NONE:
ret
createEllipse endp
moveEllipse proc
mov eax, dword ptr[vectorX]
mov ecx, dword ptr[vectorY]
add tlpoint.x, eax
add tlpoint.y, ecx
add brpoint.x, eax
add brpoint.y, ecx
ret
moveEllipse endp
updateXY proc lParam:LPARAM
mov eax, lParam
; get low word that contain x
xor ebx, ebx
mov bx, ax
mov tlpoint.x, ebx
mov brpoint.x, ebx
add brpoint.x, BALL_SIZE
; get high word that contain y
mov eax, lParam
shr eax, 16
mov tlpoint.y, eax
mov brpoint.y, eax
add brpoint.y, BALL_SIZE
ret
updateXY endp
end start
You are handling a single message in between running your GAME_LOOP. This does not bode well. Instead, drain the entire message queue in between screen updates. The solution is simple: Add
jmp MESSAGE_LOOP
right after
call DispatchMessage
extern GetModuleHandleA
extern LoadCursorA
extern RegisterClassA
extern CreateWindowExA
extern GetMessageA
extern DispatchMessageA
extern TranslateMessage
extern ExitProcess
extern PostQuitMessage
extern DefWindowProcA
section .data
MSG dq 0 ;+0 hWnd
dd 0 ;+8 message
dd 0 ;padding for next
wParam dq 0 ;+10 wParam
dq 0 ;+18 lParam
dd 0 ;+20 time
dd 0 ;+24 1st part of point structure
dd 0 ;+28 2nd part of point structure
dd 0 ;padding to bring total size to 48 bytes
WNDCLASS dd 1h+2h+40h ;+0 window class style (CS_VREDRAW+CS_HREDRAW+CS_CLASSDC)
dd 0 ;padding for next
dq WndProcTable ;+8 pointer to Window Procedure
dd 0 ;+10 no. of extra bytes to allocate after structure
dd 0 ;+14 no. of extra bytes to allocate after window instance
hInst dq 0 ;+18 handle to instance containing window procedure
dq 0 ;+20 handle to the class icon
hCursor dq 0 ;+28 handle to the class cursor
dq 6 ;+30 identifies the class background brush (6=COLOR_WINDOW+1)
dq 0 ;+38 pointer to resource name for class menu
dq win_class_name ;+40 pointer to string for window class name
win_class_name db 'simplewindow',0 ;string holding name of window class
win_id dq 0
but_id dq 0
kopf db '64 bit program', 0
class_button db 'button', 0
button_kopf db 'hjh', 0
mbt db 'this is only a test', 0
mbc db 'achtung', 0
section .text
global start
start:
sub rsp, 0x8
xor rcx, rcx
call GetModuleHandleA
mov [hInst], rax
mov rcx, 0
mov rdx, 32512
call LoadCursorA
mov [hCursor], rax
mov rcx, WNDCLASS
sub rsp, 0x20
call RegisterClassA
add rsp, 0x20
;creating main window
mov rcx, 0
mov rdx, win_class_name
mov r8, kopf
mov r9, 0x10000000+0x00080000+0x00020000
push 0
push qword[hInst]
push 0
push 0
push 512
push 512
push 256
push 256
sub rsp, 0x20
call CreateWindowExA
add rsp, 0x20
add rsp, 0x40
mov [win_id], rax
zyklus:
mov rcx, MSG
mov rdx, 0
mov r8, 0
mov r9, 0
sub rsp, 20h
call GetMessageA
add rsp, 20h
or rax, rax
jz fertig
mov rcx, MSG
call TranslateMessage
mov rcx, MSG
call DispatchMessageA
jmp zyklus
fertig:
mov rcx, [wParam]
call ExitProcess
WndProcTable:
sub rsp, 0x8
cmp edx, 0x01 ; see if it is wm_create message
jne quit
; creating button
mov rcx, 0
mov rdx, class_button
mov r8, button_kopf
mov r9, 0x40000000+0x10000000 ; child +visible
push 0
push qword[hInst]
push 0
push qword[win_id]
push 20
push 50
push 30
push 30
sub rsp, 0x20
call CreateWindowExA
add rsp, 0x20
add rsp, 0x40
mov [but_id], rax
jmp alles
quit:
cmp edx, 0x02
jne weiter
xor rcx, rcx
call PostQuitMessage
weiter:
sub rsp,20h
call DefWindowProcA
add rsp,20h
alles:
add rsp, 0x8
ret
however if you place the creation button code after creation main window code
everything works fine but it fails while processing wm_create mrssage
nasm -f win64 first.nasm -o first,obj
golink first,obj user32.dll kernel32.dll gdi32.dll
the button doesn't appear or may be not created at all
what's wrong?
I want to know what is going wrong with this piece of code
is there anybody who notices any mistake in this code
I don't know where to find mistakes
now it is solved. the thing is that main window handle is not valid in creating button after wm_create the valid handle is in rcx register (it is passed in wndproctable as the first parameter) so the right line is push rcx
now it is solved. the thing is that main window handle is not valid in creating button after wm_create the valid handle is in rcx register (it is passed in wndproctable as the first parameter) so the right line is push rcx