flat assembler
Message board for the users of flat assembler.

Index > Windows > question about message_loop

Author
Thread Post new topic Reply to topic
Syrasia



Joined: 25 Feb 2010
Posts: 11
Location: Saarland, Germany
Syrasia 31 Mar 2010, 14:06
First hi there, even I'm new at assembling, I understand the most of it (made some experiments and read some tutorials).
Lately I tried to modify the message-loop and the winProc. First I wanted to remove the translate and dispatch: translate can be removed with no problem, only the input is different, but dispatch somehow seems to decode the message, because I can't find messages in the structure as WM_MOVE or WM_CREATE. Messages like WM_PAINT or WM_KEYDOWN are send normal and I can use them (directly after getMessage).
So here are two questions:
1. can I somehow get the messages out of the structure after getmessage without dispatchmessage, or must I use the two comands?
2. because I try to get as much speed as possible, I've changed the way, how the winProc works (look the code below), is it okay to do so or are there any risks in this way?
Code:
format PE GUI 4.0
entry start

include 'win32a.inc'

include 'opengl.inc'

section '.data' data readable writeable

        hWnd            dd      ?
        msg             MSG
        buf             dd      ?

        wc              WNDCLASSEX      48, 0, winProc, 0, 0, ?, ?, ?, 0, 0, class, ?

        class           db      'syrasia-engine', 0
        title           db      'Syrasia Editor   V 0.1', 0

        WS_STYLE        equ     WS_VISIBLE or WS_SYSMENU or WS_OVERLAPPED

section '.code' code readable executable

        start:
                invoke  getModuleHandle, 0
                mov     [wc.hInstance], eax
                invoke  loadIcon, 0, IDI_APPLICATION
                mov     [wc.hIcon], eax
                mov     [wc.hIconSm], eax
                invoke  loadCursor, 0, IDC_ARROW
                mov     [wc.hCursor], eax
                invoke  registerClassEx, wc
                invoke  createWindowEx,0,class,title,WS_STYLE,8000h,8000h,512,512,NULL,NULL,[wc.hInstance],NULL
                mov     [hWnd],eax

        message_loop:
                invoke  getMessage, msg, 0, 0, 0
                cmp     eax, 1
                jb      exit
                cmp     [msg.message], WM_KEYDOWN
                je      exit
                cmp     [msg.message], WM_PAINT
                ;je     paint
                cmp     [msg.message], WM_CLOSE
                je      exit
                invoke  dispatchMessage, msg
                jmp     message_loop

        exit:
                invoke  exitProcess, 0

        winProc:                        ;using custom procedure
                mov     eax, [esp+8]    ;read out the message, letting all unaffected
                cmp     eax, WM_DESTROY
                je      winProc_closeWindow
                cmp     eax, WM_CREATE
                je      winProc_creation
                cmp     eax, 0
                je      exit

                winProc_default:
                        pop     [buf]     ;where to jump back (somewhere in dispatch)
                        invoke  defWindowProc    ;no need of param's, as the are in the stack
                        jmp     [buf]     ;and now jump back

                winProc_closeWindow:
                        jmp     exit       ;direct jump to exit

                winProc_creation:         ;demonstration piece of code
                        pop     eax       ;wold this be allowed? I keep the esp up to date:
                        add     esp, 16   ;remove unneeded param's
                        jmp     eax       ;normal jump back (like ret of proc)

section '.idata' import data readable

        library kernel,         'KERNEL32.DLL',\
                user,           'USER32.DLL',\
                gdi,            'GDI32.DLL',\
                opengl,         'OPENGL32.DLL'

        import  kernel,\
                getModuleHandle,        'GetModuleHandleA',\
                exitProcess,            'ExitProcess'

        import  user,\
                registerClassEx,          'RegisterClassExA',\
                createWindowEx,         'CreateWindowExA',\
                defWindowProc,          'DefWindowProcA',\
                getMessage,             'GetMessageA',\
                dispatchMessage,        'DispatchMessageA',\
                loadCursor,             'LoadCursorA',\

                loadIcon,               'LoadIconA',\
                postQuitMessage,        'PostQuitMessage'    

PS: I know there are (at the moment) unnecessary includes, the get important. Smile
Edit: I had commented out an importand command (winProc->je winProc_closeWindow), sorry Embarassed


Last edited by Syrasia on 31 Mar 2010, 18:25; edited 1 time in total
Post 31 Mar 2010, 14:06
View user's profile Send private message Send e-mail Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4623
Location: Argentina
LocoDelAssembly 31 Mar 2010, 14:36
Code:
                winProc_default:
                        pop     [buf]     ;where to jump back (somewhere in dispatch)
                        invoke  defWindowProc    ;no need of param's, as the are in the stack
                        jmp     [buf]     ;and now jump back    

Replace with:
Code:
                winProc_default:
                        jmp     [defWindowProc]    ;no need of param's, as the are in the stack    


Code:
                winProc_creation:         ;demonstration piece of code
                        pop     eax       ;wold this be allowed? I keep the esp up to date:
                        add     esp, 16   ;remove unneeded param's
                        jmp     eax       ;normal jump back (like ret of proc)
    

Yes you are allowed to destroy EAX, ECX and EDX, but why not just "retn 16" in replacement of all that?

I don't know if you can get rid of DispatchMessage, maybe in some situations it works but perhaps you could receive messages that are not destined to your main window? It could also process messages itself, for instance WM_TIMER it is documented as that it will call the TimerProc instead of the WindowProc when a pointer is available in the message structure. To be safe, I would use GetMessage (or PeekMessage in case you don't want to get blocked) plus DispatchMessage, I think that the speed gains cannot be noticed after several millions messages (and the human would need to time a very long run to notice the difference that could still be non conclusive due to the "noise" introduced by background processes).
Post 31 Mar 2010, 14:36
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4623
Location: Argentina
LocoDelAssembly 31 Mar 2010, 15:16
OK, decided to also test what I've said:
Code:
TIMES equ 50'000'000
format PE GUI 4.0
entry start

include 'win32a.inc'
section '.data' data readable writeable

        hWnd            dd      ?
        msg             MSG
        buf             dd      ?

        wc              WNDCLASSEX      48, 0, winProc, 0, 0, ?, ?, ?, 0, 0, class, ?

        class           db      'syrasia-engine', 0
        title           db      'Syrasia Editor   V 0.1', 0

        match iter, TIMES {
           fmt          db      'Time with DispatchMessage: %u ms.', 13, 10, 'Time without DispatchMessage: %u ms.', 13, 10, 13, 10, `iter # ' messages used', 0
        }
        szBuf           rb 256

        WS_STYLE        equ     WS_VISIBLE or WS_SYSMENU or WS_OVERLAPPED

section '.code' code readable executable

        start:
                invoke  getModuleHandle, 0
                mov     [wc.hInstance], eax
                invoke  loadIcon, 0, IDI_APPLICATION
                mov     [wc.hIcon], eax
                mov     [wc.hIconSm], eax
                invoke  loadCursor, 0, IDC_ARROW
                mov     [wc.hCursor], eax
                invoke  registerClassEx, wc
                invoke  createWindowEx,0,class,title,WS_STYLE,8000h,8000h,512,512,NULL,NULL,[wc.hInstance],NULL
                mov     [hWnd],eax

                invoke  GetTickCount
                mov     esi, eax

                mov     ebx, TIMES
                mov     [msg.message], WM_CREATE

                align   16
                @@:
                invoke  dispatchMessage, msg
                dec     ebx
                jnz     @b
                invoke  GetTickCount
                mov     edi, eax
                mov     ebx, TIMES

                align   16
        .winProc:                        ;using custom procedure
                mov     eax, [msg.message]    ;read out the message, letting all unaffected
                cmp     eax, WM_DESTROY
                ;je      .winProc_closeWindow
                cmp     eax, WM_CREATE
                je      .winProc_creation
                cmp     eax, 0
                je      exit

                .winProc_d'efault:
                        jmp     [defWindowProc]    ;no need of param's, as the are in the stack

                .winProc_closeWindow:
                        jmp     exit       ;direct jump to exit

                .winProc_creation:         ;demonstration piece of code
                 ;       ret 16

                dec     ebx
                jnz     .winProc

                invoke  GetTickCount
                mov     edx, eax
                sub     edx, edi
                mov     ecx, edi
                sub     ecx, esi

                cinvoke wsprintf, szBuf, fmt, ecx, edx
                invoke  MessageBox, 0, szBuf, title, 0
                invoke  exitProcess, 0

        message_loop:
                invoke  getMessage, msg, 0, 0, 0
                cmp     eax, 1
                jb      exit
                cmp     [msg.message], WM_KEYDOWN
                je      exit
                cmp     [msg.message], WM_PAINT
                ;je     paint
                cmp     [msg.message], WM_CLOSE
                je      exit
                invoke  dispatchMessage, msg
                jmp     message_loop

        exit:
                invoke  exitProcess, 0

        winProc:                        ;using custom procedure
                mov     eax, [esp+8]    ;read out the message, letting all unaffected
                cmp     eax, WM_DESTROY
                ;je      winProc_closeWindow
                cmp     eax, WM_CREATE
                je      winProc_creation
                cmp     eax, 0
                je      exit

                winProc_default:
                        jmp     [defWindowProc]    ;no need of param's, as the are in the stack

                winProc_closeWindow:
                        jmp     exit       ;direct jump to exit

                winProc_creation:         ;demonstration piece of code
                        ret 16

section '.idata' import data readable

        library kernel,         'KERNEL32.DLL',\
                user,           'USER32.DLL'

        import  kernel,\
                getModuleHandle,        'GetModuleHandleA',\
                GetTickCount,           'GetTickCount',\
                exitProcess,            'ExitProcess'

        import  user,\
                registerClassEx,        'RegisterClassExA',\
                createWindowEx,         'CreateWindowExA',\
                defWindowProc,          'DefWindowProcA',\
                getMessage,             'GetMessageA',\
                dispatchMessage,        'DispatchMessageA',\
                loadCursor,             'LoadCursorA',\
                loadIcon,               'LoadIconA',\
                postQuitMessage,        'PostQuitMessage',\
                MessageBox,             'MessageBoxA',\
                wsprintf,               'wsprintfA'    

Quote:
---------------------------
Syrasia Editor V 0.1
---------------------------
Time with DispatchMessage: 3438 ms.
Time without DispatchMessage: 109 ms.

50'000'000 messages used


But changing TIMES to something that would be a very pessimistic number of messages per second:
Quote:
---------------------------
Syrasia Editor V 0.1
---------------------------
Time with DispatchMessage: 15 ms.
Time without DispatchMessage: 0 ms.

100'000 messages used

(The second time was less than GetTickCount's resolution, that is why it counts 0 ms. but surely it took at least ~1 ms.)

Don't optimize where it it not worth it (unless you have the time and more importantly, the certainty that your optimization is guaranteed to work everywhere).
Post 31 Mar 2010, 15:16
View user's profile Send private message Reply with quote
Syrasia



Joined: 25 Feb 2010
Posts: 11
Location: Saarland, Germany
Syrasia 31 Mar 2010, 18:35
thx for the info (especially jmp [defWindowProc] Very Happy ),
maybe it is only little speed, but i like it to have it.
About dispatchMessage: as I found out, some mesages as WM_KEYDOWN are written directly into the message-structure, som others are not (example: after getMessage you can't use the message to know about WM_CREATE, you will need to dispatch the message to have it).
It also was something I wanted to understand, so you helped me out. Wink
Post 31 Mar 2010, 18:35
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.