I'm trying to write a simple program using OpenGL in NASM using NASMX. I have a working version of this code in C which works. The assembly version does not really work. It compiles and runs but it only shows a black screen instead of black screen with a white pixel :) ChangeDisplaySettingsA does not seem to change the display settings.
I'd rather not use NASMX but I lack the knowledge on how to do this without NASMX.
I guess there is something wrong with how I use the parameters. So what do you think? What's wrong with this code? A link to a working code sample would be great!
%include 'nasmx-1.0\inc\nasmx.inc'
%include 'nasmx-1.0\inc\win32\windows.inc'
%include 'nasmx-1.0\inc\win32\kernel32.inc'
%include 'nasmx-1.0\inc\win32\user32.inc'
%include 'nasmx-1.0\inc\win32\gdi32.inc'
%include 'nasmx-1.0\inc\win32\opengl32.inc'
%include 'nasmx-1.0\inc\win32\msvcrt.inc'
entry entrypoint
XRES equ 1024
YRES equ 786
[section .text]
proc entrypoint, ptrdiff_t argcount, ptrdiff_t cmdline
locals none
invoke ChangeDisplaySettingsA, ptrdiff_t [dmScreenSettings], 0x00000004
invoke CreateWindowExA, 0, szEdit, 0, WS_POPUP + WS_VISIBLE, 0, 0, XRES, YRES, 0, 0, 0, 0
invoke GetDC, eax
mov ptrdiff_t [hDc], eax
invoke ChoosePixelFormat, ptrdiff_t [hDc], pfd
invoke SetPixelFormat, ptrdiff_t [hDc], eax, pfd
invoke wglCreateContext, ptrdiff_t [hDc]
invoke wglMakeCurrent, ptrdiff_t [hDc], eax
invoke ShowCursor, FALSE
invoke glViewport, 0, 0, XRES, YRES
invoke glMatrixMode, 0x1701
invoke glLoadIdentity
invoke glOrtho, 0, XRES, 0, YRES, -1, 1
invoke glMatrixMode, 0x1700
invoke glLoadIdentity
.intro_loop:
invoke glColor3ub, 255, 255, 255
invoke glBegin, 0x0000
invoke glVertex2i, 100, 100
invoke glEnd
invoke SwapBuffers, ptrdiff_t [hDc]
invoke PeekMessageA, 0, 0, 0, 0, PM_REMOVE
invoke GetAsyncKeyState, VK_ESCAPE
cmp eax, dword 0
je .intro_loop
invoke ExitProcess, 0
endproc
[section .bss]
hDc: reserve(ptrdiff_t) 1
[section .data]
szEdit: declare(NASMX_TCHAR) NASMX_TEXT("edit"), 0x0
NASMX_ISTRUC pfd, PIXELFORMATDESCRIPTOR
NASMX_AT nSize, 0
NASMX_AT nVersion, 1
NASMX_AT dwFlags, 33
NASMX_AT iPixelType, 32
NASMX_AT cColorBits, 0
NASMX_AT cRedBits, 0
NASMX_AT cRedShift, 0
NASMX_AT cGreenBits, 0
NASMX_AT cGreenShift, 0
NASMX_AT cBlueBits, 0
NASMX_AT cBlueShift, 0
NASMX_AT cAlphaBits, 0
NASMX_AT cAlphaShift, 0
NASMX_AT cAccumBits, 0
NASMX_AT cAccumRedBits, 0
NASMX_AT cAccumGreenBits, 0
NASMX_AT cAccumBlueBits, 0
NASMX_AT cAccumAlphaBits, 32
NASMX_AT cDepthBits, 0
NASMX_AT cStencilBits, 0
NASMX_AT cAuxBuffers, 0
NASMX_AT iLayerType, 0
NASMX_AT bReserved, 0
NASMX_AT dwLayerMask, 0
NASMX_AT dwVisibleMask, 0
NASMX_AT dwDamageMask, 0
NASMX_IENDSTRUC
NASMX_ISTRUC dmScreenSettings, DEVMODE
NASMX_AT dmDeviceName, ""
NASMX_AT dmSpecVersion, 0
NASMX_AT dmDriverVersion, 0
NASMX_AT dmSize, 156
NASMX_AT dmDriverExtra, 0
NASMX_AT dmFields, 1572864
NASMX_AT dmOrientation, 0
NASMX_AT dmPaperSize, 0
NASMX_AT dmPaperiLength, 0
NASMX_AT dmPaperWidth, 0
NASMX_AT dmScale, 0
NASMX_AT dmCopies, 0
NASMX_AT dmDefaultSource, 0
NASMX_AT dmPrintQuality, 0
NASMX_AT dmColor, 0
NASMX_AT dmDuplex, 0
NASMX_AT dmYResolution, 0
NASMX_AT dmTTOption, 0
NASMX_AT dmCollate, 0
NASMX_AT dmFormName, ""
NASMX_AT dmUnusedPadding, 0
NASMX_AT dmBitsPerPel, 0
NASMX_AT dmPelsWidth, XRES
NASMX_AT dmPelsHeight, YRES
NASMX_AT dmDisplayFlags, 0
NASMX_AT dmDisplayFrequency, 0
NASMX_AT dmICMMethod, 0
NASMX_AT dmICMIntent, 0
NASMX_AT dmMediaType, 0
NASMX_AT dmDitherType, 0
NASMX_AT dmReserved1, 0
NASMX_AT dmReserved2, 0
NASMX_AT dmPanningWidth, 0
NASMX_AT dmPanningHeight, 0
NASMX_IENDSTRUC
Are you sure you are pushing the correct arguments? Remember that functions like glOrtho takes doubles, not floats.
Plz check
OpenGL DEMO for WIN32 for NASMX
NASMX v1.2 has this OpenGL Demo along with GL and GLUT includes.
Download from NASMX - Sourceforge.net
Related
I'm learning assembly, but I've been learning on Linux, and it's been very interwoven with C/C++ since I understand C/C++.
However, now, I want to write a program in assembly on my Windows computer that makes a call to a function that runs a shell command, and hopefully without including any libraries since I want this executable to be as small as possible. (A simple C++ executable I made which included cstdlib is 32 KB while I typed barely any code at all.)
I want to essentially write this program but in assembly:
#include <cstdlib>
int main()
{
system("echo ABCDEFG> msg.txt");
system("type msg.txt");
return 0;
}
So far, I have installed NASM and MinGW and I'm trying to use them [Edit: I am now trying to use MASM instead, with Visual Studio], but nothing works and I assume it's because Windows has its own stuff from Microsoft that obviously aren't in Linux, but none of the online resources I've come across have successfully compiled with what I was trying to do. It also doesn't seem to understand the statement extern system, so I think that this might be a C/C++ library thing (from cstdlib).
Also, in some cases I encountered an error where it said the "character constant is too long". I assume it's referring to the string; in the real program, the string to echo is much longer than what's in the example above.
I also had an issue apparently with the .obj file that was generated.
So, basically, all I need is how to turn the above program into assembly for Windows, and how to get NASM and MinGW to turn it into an executable without giving me errors.
Edit: After a few days of researching, I have decided I don't know what I'm doing wrong and I can't figure out what is right.
I've tried Visual Studio now, but once again, it doesn't understand extern system.
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode: DWORD
.data
Var db 'dir && pause', 0
.code
extern system
main PROC
push ebp
mov ebp, esp
sub esp, 32
lea ecx, [Var]
call system
xor eax, eax
INVOKE ExitProcess, 0
main ENDP
END main
As I mentioned in the comments, Windows does have a system command. It's located in MSVCRT.dll, so you'll need to link with msvcrt.lib to resolve the external reference.
The error you are getting from "line 11" is due to incorrectly defining the external, which is odd since you're correctly doing the same for ExitProcess (which is also an external) just a few lines before.
32k may sound big, but Windows works in 4k pages these days, allowing it set page protection bits (read-only pages, executable pages, etc). One page for executable code, one for data, one for constants, imports, exports, debug info, exception info, etc. 8 pages doesn't seem that outrageous by today's standards.
But as I also mentioned, there are hacks one can use to reduce the size of the executable if there's some compelling reason to do so. This sample (built with NASM version 2.15.05 using nasm.exe doit.asm -o doit.exe) is 1,184 bytes. When you run it, nothing seems to happen (no cmd window opens) and it's really quick. But you'll see that foo.xxx gets created and contains the output from the dir > foo.xxx command embedded in the code.
There's a lot of gobbledygook here that the linker normally handles for you. The interesting bits start at ENTRY:. cmd is defined near the end of the code.
The stealthy nature of this code combined with the small size opens the possibility of using this code for mischief. I'm going to assume that's not your intent.
; Check for NASM version at least 2.15.05
%if __?NASM_VERSION_ID?__ < 0x0020F0500
%error "Newer version of nasm required"
%endif
%define RoundTo(a, b) ((((a) + ((b) - 1)) / (b)) * (b))
%define Stringify(&val) val
%macro NameEntry 2
%1__ dw %2
db Stringify(%1), 0
%endmacro
salign equ 1000h ; Page size in memory
falign equ 200h ; Page size in file
imageBase equ 400000h ; Requested load address
BITS 16
section headers start=0
startoffile:
; MZ header https://wiki.osdev.org/MZ
dw "MZ" ; Signature
dw (dosBlkSize - mzStructSize) % 512 ; Bytes on last page
dw RoundTo(dosBlkSize, 512) / 512 ; # of 512 byte pages
dw 0 ; Relocation items
dw RoundTo(mzStructSize, 16) / 16 ; Header size in paragraphs
dw 0 ; Minimum allocation
dw 0xffff ; Maximum allocation in paragraphs (1M).
dw 0 ; Initial SS
dw 0xb8 ; Initial SP
dw 0 ; Checksum
dw 0 ; Initial IP
dw 0 ; Initial CS
dw 0 ; Relocation table
dw 0 ; Overlay
dq 0 ; Reserved
dw 0 ; OEM identifier
dw 0 ; OEM info
times 20 db 0 ; Reserved
dd PEHDR ; PE header start
mzStructSize equ $ - $$ ; aka 64
dosstartcode: ; Print the error and exit
push cs
pop ds
mov dx, dosmsg - dosstartcode
mov ah, 0x9
int 0x21 ; Show string up to '$'
mov ax, 4c01h
int 0x21 ; Exit process with error code 1
dosmsg db `This program cannot be run in DOS mode.\r\r\n$`
dosBlkSize equ $ - $$
ALIGN 16
; From https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
PEHDR:
dd "PE" ; signature
dw 8664h ; machine x64
dw SectionsCount ; # of sections
dd __POSIX_TIME__ ; timedatestamp
dd 0 ; pointer to symtab - deprecated
dd 0 ; # symtab entries
dw opthdrSize ; size of optional header
dw 2h ; flags: Executable
OPTHDR:
dw 20Bh ; magic
db 0 ; maj linker ver
db 0 ; minor linker ver
dd codeSizeS ; total memory code size
dd rdataSizeS ; total memory init data size
dd 0 ; total uninit data size
dd ENTRY ; entrypoint RVA
dd section..text.start ; base of code in file
dq imageBase ; image base
dd salign ; section address alignment
dd falign ; section pos alignment
dw 10 ; major OS version
dw 0 ; minor OS version
dw 0 ; major image ver
dw 1 ; minor image ver
dw 6 ; major subsystem ver
dw 2 ; minor subsystem ver
dd 0 ; win32 version value = 0
dd fileSize ; size of image in memory
dd headersSizeF ; size of DOS stub + PE header + sections
dd 0 ; checksum
dw 2 ; subsystem: GUI
dw 8160h ; dll characteristics: HighEntropy, Relocatable, NX, TS aware
dq 100h ; max stack
dq 100h ; min stack
dq 100h ; max heap
dq 100h ; min heap
dd 0 ; loader flag
HeaderDirectories:
dd HeaderDirectoryCount ; number of directories
; Address, Size
dd 0, 0 ; Export
dd ImportsDir, ImportsDirSize ; Import
dd 0, 0 ; Resource
dd 0, 0 ; Exception
dd 0, 0 ; Certificates
dd 0, 0 ; Base Relocation
dd 0, 0 ; Debug
dd 0, 0 ; Architecture
dd 0, 0 ; Global Pointer
dd 0, 0 ; Thread Storage
dd 0, 0 ; Load Configuration
dd 0, 0 ; Bound Import
dd IATStart, IATSize ; Import Address Table
dd 0, 0 ; Delay Import
dd 0, 0 ; COM Descriptor
dd 0, 0 ; Reserved
HeaderDirectorySize equ $ - HeaderDirectories
HeaderDirectoryCount equ HeaderDirectorySize / 8
opthdrSize equ $ - OPTHDR
startOfSections:
dq ".text"
dd codeSizeS ; size in memory pages
dd ENTRY ; addr RVA (memory offset)
dd codeSize ; length
dd section..text.start ; pos (file offset)
dd 0 ; relocations addr
dd 0 ; linenum addr
dw 0 ; relocations count
dw 0 ; linenum count
dd 030000020h ; flags: Code, Shared, Execute Only
dq ".rdata"
dd rdataSizeS ; size in memory pages
dd RDATA ; addr RVA (memory offset)
dd rdataSize ; length
dd section.rdata.start ; pos (file offset)
dd 0 ; relocations addr
dd 0 ; linenum addr
dw 0 ; relocations count
dw 0 ; linenum count
; Take advantage of the fact that the loader cheats and
; writes imports to readonly pages # startup
dd 040000040h ; flags: Initialized Data, Read Only
SectionsSize equ $ - startOfSections
SectionsCount equ SectionsSize / 40
ALIGN 16
headersSizeF equ RoundTo($ - $$, falign)
headersSizeS equ RoundTo($ - $$, salign)
BITS 64
DEFAULT REL ; so we don't have to keep adding imageBase
SECTION .text vstart=headersSizeS align=falign follows=headers
ENTRY:
sub rsp, 28h
lea rcx, [cmd] ; LPCSTR lpCmd
call [system]
; Use the return value from the call to system
mov ecx, eax
call [ExitProcess]
codeSize equ $ - $$
codeSizeS equ RoundTo(codeSize, salign)
SECTION rdata vstart=headersSizeS+codeSizeS align=falign
RDATA:
IATStart:
; Import Address Table
Kernel32TableA:
ExitProcess dq ExitProcess__
MSVCRTTableA:
system dq system__
IATSize equ $ - IATStart
ImportsDir:
dd Kernel32TableL, 0, 0, kernel32dll, Kernel32TableA
dd MSVCRTTableL, 0, 0, MSVCRTdll, MSVCRTTableA
ImportsDirSize equ $ - ImportsDir
; Kernel32 Import Lookup Table
Kernel32TableL:
dq ExitProcess__
dq 0 ; end of table marker
; Name, Hint
NameEntry ExitProcess, 164h
; MSVCRT Import Lookup Table
MSVCRTTableL:
dq system__
dq 0 ; end of table marker
; Name, Hint
NameEntry system, 4e0h
kernel32dll db "KERNEL32.dll", 0
MSVCRTdll db "MSVCRT.dll", 0
; Constant data
cmd db "dir > foo.xxx", 0h
ALIGN 16
rdataSize equ $ - RDATA
rdataSizeS equ RoundTo(rdataSize, salign)
fileSize equ RDATA + rdataSizeS
You usage of extern does not make any sense, extern in masm means you are calling an API function (like printf in c) not a executable file. The first comment is correct. In the win32 api a process launched from anther process you need the CreateProcessA or CreateProcessW function and you need to setup a PROCESS_INFORMATION structure to pass it. You might have to set up other structures too, I don't remember, then you call it if you pushed to arguments to the stack manually or simply invoke it and let the assembler handle that. I would recommend getting a copy of masm32, that should make it easy, there is likely already a sample in it or on the internet.
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.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I'm looking for a software that can losslessy compress a small amount of noisy data; example:
ZmNiYWNma3F5gYqSmqCkpqenpKGdmJONiIN/e3d1c3FxcXFxcnN0dXZ3eXp7fHx9fn5/gIGDhISFhYWFhIOCgYGAgICBgoOEhYeIiYmJiYiGhIF+fHl3dHNyc3N1d3p9gIOGiYuMjY2NjIuKiIeFg4GAfnx7eXl4eHl5enx9fn5/gICAgYGBgYGBgYGBgoKDhISEhISEhIOCgoGAgH9/fn5+fn5/gICAgICAgICAgICAgICAf39/gICBgoOFhoeIiIiIiIeGhYOCgH99fHt6enp6e3x9foCAgoKDg4ODgoKBgH59fHt7e3t8fX5/gIKDhIWFhoaGhoaFhISDgoKBgQ==
Original data: 345B (100%),
gzip: 280B (81%),
bzip2: 289B (84%),
lzop: 415B (120%),
Are there any other methods I should try?
Since the data is Base64 encoded (every 3 bytes become 4 bytes), the first step would be to decode it (the compressed data will be binary anyway):
344 bytes -> 256 bytes
Then, a simple test with standard winzip here shows a compression to 170 bytes (COMP_DEFLATE block). You should get about the same with gzip/zlib.
This could probably made somewhat smaller with a higher compression factor.
Compressing the original data gives 243 bytes (data block inside the .zip file, the full zip file is 359 bytes, but you don't need all that extra data).
So, using zlib on the decoded data, should compress that to ±170 bytes.
Looking at the decoded data, an even better compression would be possible. But that depends on the other data having the same structure.
Hex dump of the decoded data (a lot of values are repeating, or only changing slightly):
66 63 62 61 63 66 6B 71 79 81 8A 92 9A A0 A4 A6
A7 A7 A4 A1 9D 98 93 8D 88 83 7F 7B 77 75 73 71
71 71 71 71 72 73 74 75 76 77 79 7A 7B 7C 7C 7D
7E 7E 7F 80 81 83 84 84 85 85 85 85 84 83 82 81
81 80 80 80 81 82 83 84 85 87 88 89 89 89 89 88
86 84 81 7E 7C 79 77 74 73 72 73 73 75 77 7A 7D
80 83 86 89 8B 8C 8D 8D 8D 8C 8B 8A 88 87 85 83
81 80 7E 7C 7B 79 79 78 78 79 79 7A 7C 7D 7E 7E
7F 80 80 80 81 81 81 81 81 81 81 81 81 82 82 83
84 84 84 84 84 84 84 83 82 82 81 80 80 7F 7F 7E
7E 7E 7E 7E 7F 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 7F 7F 7F 80 80 81 82 83 85 86 87 88
88 88 88 88 87 86 85 83 82 80 7F 7D 7C 7B 7A 7A
7A 7A 7B 7C 7D 7E 80 80 82 82 83 83 83 83 82 82
81 80 7E 7D 7C 7B 7B 7B 7B 7C 7D 7E 7F 80 82 83
84 85 85 86 86 86 86 86 85 84 84 83 82 82 81 81
Only after a quick look: it should be possible to reach about 2 to 3 bits per byte on average, resulting in 64 to 96 bytes.
A closer look at the data:
Most values don't change that much. If all data is similar to this, a high compression rate could be achieved using some custom code. For example, the differences could be stored in 1, 2, 3 or 4 bits depending on the block of data (4 bits only needed for the first data points). Another approach, instead of full custom code, would be to compress the differences (delta values) with an existing algorithm (zlib, Huffman coding, and others).
Decimal values with 2 rounds of delta-encoding:
102
99 -3
98 -1 2
97 -1 0
99 2 3
102 3 1
107 5 2
113 6 1
121 8 2
129 8 0
138 9 1
146 8 -1
154 8 0
160 6 -2
164 4 -2
166 2 -2
167 1 -1
167 0 -1
164 -3 -3
161 -3 0
157 -4 -1
152 -5 -1
147 -5 0
141 -6 -1
136 -5 1
131 -5 0
127 -4 1
123 -4 0
119 -4 0
117 -2 2
115 -2 0
113 -2 0
113 0 2
113 0 0
113 0 0
113 0 0
114 1 1
115 1 0
116 1 0
117 1 0
118 1 0
119 1 0
121 2 1
122 1 -1
123 1 0
124 1 0
124 0 -1
125 1 1
126 1 0
126 0 -1
127 1 1
128 1 0
129 1 0
131 2 1
132 1 -1
132 0 -1
133 1 1
133 0 -1
133 0 0
133 0 0
132 -1 -1
131 -1 0
130 -1 0
129 -1 0
129 0 1
128 -1 -1
128 0 1
128 0 0
129 1 1
130 1 0
131 1 0
132 1 0
133 1 0
135 2 1
136 1 -1
137 1 0
137 0 -1
137 0 0
137 0 0
136 -1 -1
134 -2 -1
132 -2 0
129 -3 -1
126 -3 0
124 -2 1
121 -3 -1
119 -2 1
116 -3 -1
115 -1 2
114 -1 0
115 1 2
115 0 -1
117 2 2
119 2 0
122 3 1
125 3 0
128 3 0
131 3 0
134 3 0
137 3 0
139 2 -1
140 1 -1
141 1 0
141 0 -1
141 0 0
140 -1 -1
139 -1 0
138 -1 0
136 -2 -1
135 -1 1
133 -2 -1
131 -2 0
129 -2 0
128 -1 1
126 -2 -1
124 -2 0
123 -1 1
121 -2 -1
121 0 2
120 -1 -1
120 0 1
121 1 1
121 0 -1
122 1 1
124 2 1
125 1 -1
126 1 0
126 0 -1
127 1 1
128 1 0
128 0 -1
128 0 0
129 1 1
129 0 -1
129 0 0
129 0 0
129 0 0
129 0 0
129 0 0
129 0 0
129 0 0
130 1 1
130 0 -1
131 1 1
132 1 0
132 0 -1
132 0 0
132 0 0
132 0 0
132 0 0
132 0 0
131 -1 -1
130 -1 0
130 0 1
129 -1 -1
128 -1 0
128 0 1
127 -1 -1
127 0 1
126 -1 -1
126 0 1
126 0 0
126 0 0
126 0 0
127 1 1
128 1 0
128 0 -1
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
128 0 0
127 -1 -1
127 0 1
127 0 0
128 1 1
128 0 -1
129 1 1
130 1 0
131 1 0
133 2 1
134 1 -1
135 1 0
136 1 0
136 0 -1
136 0 0
136 0 0
136 0 0
135 -1 -1
134 -1 0
133 -1 0
131 -2 -1
130 -1 1
128 -2 -1
127 -1 1
125 -2 -1
124 -1 1
123 -1 0
122 -1 0
122 0 1
122 0 0
122 0 0
123 1 1
124 1 0
125 1 0
126 1 0
128 2 1
128 0 -2
130 2 2
130 0 -2
131 1 1
131 0 -1
131 0 0
131 0 0
130 -1 -1
130 0 1
129 -1 -1
128 -1 0
126 -2 -1
125 -1 1
124 -1 0
123 -1 0
123 0 1
123 0 0
123 0 0
124 1 1
125 1 0
126 1 0
127 1 0
128 1 0
130 2 1
131 1 -1
132 1 0
133 1 0
133 0 -1
134 1 1
134 0 -1
134 0 0
134 0 0
134 0 0
133 -1 -1
132 -1 0
132 0 1
131 -1 -1
130 -1 0
130 0 1
129 -1 -1
129 0 1
Here is a complete set of classes that can be used to compress this data with the following approach:
First Base64 decode the string to get bytes (345 -> 256 bytes)
Then delta-encode the bytes (meaning, subtract one byte from the previous, storing the results)
Another round of delta-encoding (but 3 was worse than 2)
Then compress the deltas using Huffman compression
This approach got down to 76 bytes including the necessary overhead to decompress later on.
A full Mercurial repository with the code can be found here.
Note! The code likely contains bugs around edge-cases such as empty or near-empty inputs. A suite of unit-tests can be found in the above linked repository but more testing is likely needed in order to trust this code for production usage.
Test program:
static void Main(string[] args)
{
string inputString = "ZmNiYWNma3F5gYqSmqCkpqenpKGdmJONiIN/e3d1c3FxcXFxcnN0dXZ3eXp7fHx9fn5/gIGDhISFhYWFhIOCgYGAgICBgoOEhYeIiYmJiYiGhIF+fHl3dHNyc3N1d3p9gIOGiYuMjY2NjIuKiIeFg4GAfnx7eXl4eHl5enx9fn5/gICAgYGBgYGBgYGBgoKDhISEhISEhIOCgoGAgH9/fn5+fn5/gICAgICAgICAgICAgICAf39/gICBgoOFhoeIiIiIiIeGhYOCgH99fHt6enp6e3x9foCAgoKDg4ODgoKBgH59fHt7e3t8fX5/gIKDhIWFhoaGhoaFhISDgoKBgQ==";
byte[] original = Convert.FromBase64String(inputString);
Console.WriteLine($"Original String: {inputString.Length}");
Console.WriteLine($"Original bytes: {original.Length}");
byte[] deltaEncoded = DeltaEncoderDecoder.Encode(original, 2);
byte[] compressed = HuffmanCompression.Compress(deltaEncoded);
Console.WriteLine($"Compressed bytes: {compressed.Length}");
byte[] deltaDecoded = HuffmanCompression.Decompress(compressed);
byte[] decompressed = DeltaEncoderDecoder.Decode(deltaDecoded, 2);
Console.WriteLine($"Decompressed bytes: {decompressed.Length}");
Console.WriteLine($"Decompressed == original: {decompressed.Length == original.Length && Enumerable.Range(0, original.Length).All(index => original[index] == decompressed[index])}");
}
Output:
Original String: 344
Original bytes: 256
Compressed bytes: 76
Decompressed bytes: 256
Decompressed == original: True
Here are the necessary classes to both compress and decompress the data:
public static class HuffmanCompression
{
internal const byte CompressedSignature = 255;
internal const byte UncompressedSignature = 0;
[NotNull]
public static byte[] Compress([NotNull] byte[] input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (input.Length == 0)
return input;
var rootNode = GetNodesFromRawInput(input);
var bitStrings = GetBitStringsFromTree(rootNode);
var output = new MemoryStream(input.Length);
var writer = new BitStreamWriter(output);
writer.Write(CompressedSignature);
writer.Write(input.Length);
WriteNodes(writer, rootNode);
WriteStrings(writer, bitStrings, input);
writer.Flush();
if (output.Length < input.Length + 1)
return output.ToArray();
return EncodeAsUncompressed(input);
}
[NotNull]
private static byte[] EncodeAsUncompressed([NotNull] byte[] input)
{
var output = new MemoryStream();
output.WriteByte(UncompressedSignature);
output.Write(input, 0, input.Length);
return output.ToArray();
}
private static void WriteStrings([NotNull] BitStreamWriter writer, [NotNull] string[] bitStrings, [NotNull] byte[] input)
{
foreach (byte value in input)
{
Assume(bitStrings[value] != null);
foreach (char bitChar in bitStrings[value])
writer.Write(bitChar == '1');
}
}
private static void WriteNodes([NotNull] BitStreamWriter writer, [NotNull] Node node)
{
if (node.Left == null)
{
writer.Write(false);
writer.Write(node.Value);
}
else
{
Assume(node.Right != null);
writer.Write(true);
WriteNodes(writer, node.Left);
WriteNodes(writer, node.Right);
}
}
[NotNull, ItemNotNull]
private static string[] GetBitStringsFromTree([NotNull] Node node)
{
var result = new string[256];
TraverseToGetBitStringsFromTree(node, string.Empty, result);
return result;
}
private static void TraverseToGetBitStringsFromTree([NotNull] Node node, [NotNull] string prefix, [NotNull, ItemNotNull] string[] dictionary)
{
if (node.Left != null)
{
Assume(node.Right != null);
TraverseToGetBitStringsFromTree(node.Left, prefix + "0", dictionary);
TraverseToGetBitStringsFromTree(node.Right, prefix + "1", dictionary);
}
else
dictionary[node.Value] = prefix;
}
[NotNull]
private static Node GetNodesFromRawInput([NotNull] byte[] input)
{
var occurances = new int[256];
foreach (byte value in input)
occurances[value]++;
var nodes = new List<Node>(256);
for (int index = 0; index < 256; index++)
if (occurances[index] > 0)
nodes.Add(new Node
{
Occurances = occurances[index],
Value = (byte)index
});
while (nodes.Count > 1)
{
nodes.Sort((n1, n2) =>
{
Assume(n1 != null && n2 != null);
return n1.Occurances.CompareTo(n2.Occurances);
});
Assume(nodes[0] != null && nodes[1] != null);
nodes[0] = new Node
{
Left = nodes[0],
Right = nodes[1],
Occurances = nodes[0].Occurances + nodes[1].Occurances
};
nodes.RemoveAt(1);
}
Assume(nodes[0] != null);
return nodes[0];
}
[NotNull]
public static byte[] Decompress([NotNull] byte[] input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (input.Length == 0)
return input;
if (input[0] != CompressedSignature)
return DecodeUncompressed(input);
var reader = new BitStreamReader(new MemoryStream(input));
reader.ReadByte(); // skip signature
int length = reader.ReadInt32();
var rootNode = ReadNodes(reader);
var output = new byte[length];
for (int index = 0; index < length; index++)
output[index] = DecompressOneByte(reader, rootNode);
return output;
}
private static byte DecompressOneByte([NotNull] BitStreamReader reader, [NotNull] Node node)
{
while (node.Left != null)
{
if (reader.ReadBit())
node = node.Right;
else
node = node.Left;
Assume(node != null);
}
return node.Value;
}
[NotNull]
private static Node ReadNodes([NotNull] BitStreamReader reader)
{
if (reader.ReadBit())
return new Node
{
Left = ReadNodes(reader),
Right = ReadNodes(reader)
};
return new Node
{
Value = reader.ReadByte()
};
}
[NotNull]
private static byte[] DecodeUncompressed([NotNull] byte[] input)
{
return input.Skip(1).ToArray();
}
}
public class BitStreamReader
{
[NotNull]
private readonly MemoryStream _Source;
private byte _Buffer;
private int _InBuffer;
public BitStreamReader([NotNull] MemoryStream source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
_Source = source;
}
public bool ReadBit()
{
if (_InBuffer == 0)
FillBuffer();
return (_Buffer & BitStreamConstants.BitMasks[8 - _InBuffer--]) != 0;
}
public byte ReadByte()
{
if (_InBuffer == 8)
{
_InBuffer = 0;
return _Buffer;
}
return (byte)((ReadBit() ? 128 : 0) | (ReadBit() ? 64 : 0) | (ReadBit() ? 32 : 0) | (ReadBit() ? 16 : 0) | (ReadBit() ? 8 : 0) | (ReadBit() ? 4 : 0) | (ReadBit() ? 2 : 0) | (ReadBit() ? 1 : 0));
}
public int ReadInt32()
{
int result = 0;
if (ReadBit())
result |= ReadByte();
if (ReadBit())
result |= ReadByte() << 8;
if (ReadBit())
result |= ReadByte() << 16;
if (ReadBit())
result |= ReadByte() << 24;
return result;
}
private void FillBuffer()
{
int value = _Source.ReadByte();
if (value < 0)
throw new InvalidOperationException("Read past end of source stream");
_Buffer = (byte)value;
_InBuffer = 8;
}
}
public class BitStreamWriter
{
[NotNull]
private readonly MemoryStream _Target;
private byte _Buffer;
private int _InBuffer;
public BitStreamWriter([NotNull] MemoryStream target)
{
if (target == null)
throw new ArgumentNullException(nameof(target));
_Target = target;
}
public void Flush()
{
if (_InBuffer == 0)
return;
_Target.WriteByte(_Buffer);
_Buffer = 0;
_InBuffer = 0;
}
public void Write(bool bit)
{
unchecked
{
if (bit)
_Buffer = (byte)(_Buffer | 1 << (7 - _InBuffer));
if (++_InBuffer == 8)
Flush();
}
}
public void Write(byte value)
{
for (int index = 0; index < 8; index++)
Write((value & BitStreamConstants.BitMasks[index]) != 0);
}
public void Write(int value)
{
byte b0 = (byte)(value & 0xff);
byte b1 = (byte)((value >> 8) & 0xff);
byte b2 = (byte)((value >> 16) & 0xff);
byte b3 = (byte)((value >> 24) & 0xff);
Write(b0 != 0);
if (b0 != 0)
Write(b0);
Write(b1 != 0);
if (b1 != 0)
Write(b1);
Write(b2 != 0);
if (b2 != 0)
Write(b2);
Write(b3 != 0);
if (b3 != 0)
Write(b3);
}
}
internal static class BitStreamConstants
{
[NotNull]
public static readonly byte[] BitMasks = { 128, 64, 32, 16, 8, 4, 2, 1 };
public const byte CompressedSignature = 255;
}
public static class DeltaEncoderDecoder
{
[NotNull]
public static byte[] Encode([NotNull] byte[] input, int iterations)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var output = new byte[input.Length];
Buffer.BlockCopy(input, 0, output, 0, input.Length);
while (iterations-- > 0)
{
byte previous = 0;
for (int index = 0; index < output.Length; index++)
{
byte current = output[index];
output[index] = (byte)(current - previous);
previous = current;
}
}
return output;
}
[NotNull]
public static byte[] Decode([NotNull] byte[] input, int iterations)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var output = new byte[input.Length];
Buffer.BlockCopy(input, 0, output, 0, input.Length);
while (iterations-- > 0)
{
byte previous = 0;
for (int index = 0; index < output.Length; index++)
{
output[index] = (byte)(previous + output[index]);
previous = output[index];
}
}
return output;
}
}
I am trying to learn more about assembly and disassembly.
My goal is to modify the way a specific address is being written using a debugger (olly). Preferably by incrementing it by a number (20, 50, etc..) I can identify the address of the floating point number (in this case located at 33B7420C).
When I set a breakpoint on memory access write it brings me to 00809B2E which has the following assembly:
FSTP DWORD PTR DS:[ESI+1224]
What exactly is it doing in this address? I know that the FPU register has the number i'm looking for but not sure what all this address is doing.
The closest I come to googling is:
What does MOV EAX, DWORD PTR DS:[ESI] mean and what does it do?
A copy of the registers shows the following:
EAX 00000000
ECX 00A16E40 EZ.00A16E40
EDX FFFFFFFF
EBX 33B74578
ESP 0018FA90
EBP 00000000
ESI 33B72FE8
EDI 33B74578
EIP 00809B2E <EZ.Breakpoint for time>
C 0 ES 002B 32bit 0(FFFFFFFF)
P 0 CS 0023 32bit 0(FFFFFFFF)
A 0 SS 002B 32bit 0(FFFFFFFF)
Z 0 DS 002B 32bit 0(FFFFFFFF)
S 0 FS 0053 32bit 7EFDD000(FFF)
T 0 GS 002B 32bit 0(FFFFFFFF)
D 0
O 0 LastErr ERROR_SUCCESS (00000000)
EFL 00210202 (NO,NB,NE,A,NS,PO,GE,G)
ST0 valid 1150.0000000000000000
ST1 zero 0.0
ST2 zero 0.0
ST3 empty 64.951911926269531250
ST4 empty -13.250000000000000000
ST5 empty 64.951911926269531250
ST6 empty 64.951911926269531250
ST7 empty 0.0239995196461677551
3 2 1 0 E S P U O Z D I
FST 2927 Cond 0 0 0 1 Err 0 0 1 0 0 1 1 1 (LT)
FCW 027F Prec NEAR,53 Mask 1 1 1 1 1 1
Any help would be appreciated, Thanks!
FSTP stores a floating point number from the top of the floating-point register stack (ST0) to the designated memory region. Using the DWORD modifier means that a 32-bit float will be written. The P suffix indicates that the floating-point register stack will be popped after the operation.
So, in effect, this instruction puts 1150.0 (as a 32-bit float) at DS:[ESI+1224], then pops the register stack (which causes ST0 = 0.0, ST1 = 0.0, ST2 = <empty>, etc.).
It's storing ST0 (1150.0) in single-precision to your address. And popping said value from the FPU stack.
To add 50 (0x32 being hex for 50):
mov eax, dword[ds:esi+0x1224]
add eax, 0x32
mov dword[ds:esi+0x1224], eax
I try to create the simplest WinAPI window using assembly NASM.
I have problem with Window Proc. Look at commented lines:
%macro API 2
import %1 %2
extern %1
%endmacro
API GetModuleHandleA, kernel32.dll
API LoadIconA,user32.dll
API LoadCursorA,user32.dll
API RegisterClassExA, user32.dll
API CreateWindowExA, user32.dll
API MessageBoxA, user32.dll
API SendMessageA, user32.dll
API DefWindowProcA, user32.dll
API ExitProcess, kernel32.dll
API GetMessageA, user32.dll
API DispatchMessageA, user32.dll
API TranslateMessage,user32.dll
API ShowWindow,user32.dll
API UpdateWindow,user32.dll
API GetCommandLineA,kernel32.dll
API PostQuitMessage,user32.dll
segment .data USE32
windowName db "Hello world!", 0
cmdLine dd 0
hWnd dd 0
hInst dd 0
hCursor dd 0
className db "moje_okno",0
blad db "Blad!!!",0
segment .bss
struc WNDCLASSEX
.sSize resb 4
.style resb 4
.wndProc resb 4
.clsExtra resb 4
.wndExtra resb 4
.hInstance resb 4
.hIcon resb 4
.hCursor resb 4
.background resb 4
.sMenuName resb 4
.sClassName resb 4
.hIconSm resb 4
endstruc
wndClass istruc WNDCLASSEX
iend
global ..start
segment .text USE32
..start:
push 0
call [GetModuleHandleA]
mov dword [hInst], eax ; application handle
push dword 0x00007f00 ; MAKEINTRESOURCE(32512)
push dword 0
call [LoadCursorA]
mov dword [hCursor], eax ; cursor handle
mov dword [wndClass + WNDCLASSEX.sSize], dword 48 ; struct size
mov dword [wndClass + WNDCLASSEX.style], dword 0 ; style
mov dword [wndClass + WNDCLASSEX.wndProc], wndproc ; window proc
mov dword [wndClass + WNDCLASSEX.clsExtra], dword 0
mov dword [wndClass + WNDCLASSEX.wndExtra], dword 0
mov eax, dword [hInst]
mov dword [wndClass + WNDCLASSEX.hInstance], eax ; handle
mov dword [wndClass + WNDCLASSEX.hIcon], dword 0
mov eax, dword [hCursor]
mov dword [wndClass + WNDCLASSEX.hCursor], eax
mov dword [wndClass + WNDCLASSEX.background], dword 0
mov dword [wndClass + WNDCLASSEX.sMenuName], dword 0
mov dword [wndClass + WNDCLASSEX.sClassName], className ; class name
mov dword [wndClass + WNDCLASSEX.hIconSm], dword 0
push wndClass
call [RegisterClassExA]
call near sprawdz_blad ; check return value of RegisterClassExA
push 0 ; param
push dword [hInst] ; handle
push 0 ;hMenu
push 0 ;parent
push 200 ;height
push 200 ;width
push 200 ;y
push 200 ;x
push 0 ;style
push className ;window name
push className ;window class
push 0 ;extended style
call [CreateWindowExA]
push eax
call near sprawdz_blad ;check return value of CreateWindowExA. RETURNS 0
push 0
call [ExitProcess]
wndproc:
; HERE I NEED ACCESS TO WINDOW PROC PARAMETERS: HWND, MSG, WPARAM, LPARAM
; I TRIED:
pop eax
pop ebx
pop ecx
pop edx
; BUT IT DOESN'T WORK
; THERE ARE NOT RIGHT VALUES IN THESE REGISTRIES
ret
box:
push 0
push blad
push blad
push 0
call [MessageBoxA]
ret
sprawdz_blad:
pop eax
cmp eax, 0
jne ok ; if function returns 0 everything is allright
push 0
push blad
push blad
push 0
call [MessageBoxA]
push 1
call [ExitProcess]
ok:
ret
I try to make it work for hours but I'm out of ideas.
Please help.
Greetings, Michal.
A called subroutine, wheether you call it yourself or it's called by Windows (like wndproc) has its return address as the first thing on the stack. You do NOT want to pop this! To access the parameters, you need to look farther up the stack. Try something like...
wndproc:
mov eax, [esp + 4]
mov ebx, [esp + 8]
; etc...
See if that helps...
Best,
Frank