News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

message pump variant X64

Started by mikeburr, December 23, 2020, 11:46:56 AM

Previous topic - Next topic

mikeburr

ML64 message pump using a jump table ....................

i thought id try a variation of the message loop inspired by an example program [not this example didnt have editable fields ]
the edit fields are provided with defaults and every thing works fine .. except [detailed later ]


im interested to know if anyone has tried anything like this and can provide some insight

i tried setting up a version of a simple GCD program with a slightly different message pump which i think derived from a 64 bit example
[though im not sure where this came from)
sketch of message pump


?????????????????????    initialisation  ???????????????????????
   ; ---------------------------------------------------------------
    ; fill array with address of default processing label in WndProc
    ; ---------------------------------------------------------------
         mov rdi_save, rdi
         mov rdi, OFFSET wMsgs       ; array address
         mov rax, OFFSET DEF_MSG_HANDLER   ; default processing label in WndProc
         mov rcx, 800h ; WM  messages up to WM_USER           
        rep stosq
          mov  rdi, rdi_save

    ; ----------------------------------------------
    ; write address of each procedure
    ; associated with a message to process
    ; ----------------------------------------------
         mov rax, OFFSET wMsgs

        ;  SetAddress WM_COMMAND
          lea rbx,WM_COMMAND_EVENT ; these being procs
          mov [rax+WM_COMMAND*8], rbx   

          lea rbx,WM_CLEAR_EVENT  ; these being procs
          mov [rax+WM_CLEAR*8], rbx

          lea ......         
          ..................
         and so on for each event you wish to track
????????????????????????????????????????????????????????????
message loop

.....

    xor rsi, rsi
    lea rdi, msg

    jmp @F
align 10h
  StartLoop:
               mov rcx,rdi
          call  DispatchMessage   ; equivalent   invoke DispatchMessage,rdi

  @@:

              mov rcx,rdi
              mov rdx, rsi
              mov r8, rsi
              mov r9, rsi
          call  GetMessage       ;  equivalent  invoke GetMessage,rdi,rsi,rsi,rsi

   
    cmp rax, rsi                 ; exit on zero
    jne StartLoop

  ......
?????????????????????????????????????????????????????????????????????????????????????
******************************************************************************************
*for comparison a traditional message loop [i think this is one of your examples Hutch ]
*
*    mov pmsg, ptr$(msg)                     ; get the msg structure address
*    jmp gmsg                                ; jump directly to GetMessage()
*align 10h
*  mloop:
*    invoke TranslateMessage,pmsg
*    invoke DispatchMessage,pmsg
*align 10h
*  gmsg:
*    test rax, rv(GetMessage,pmsg,0,0,0)     ; loop until GetMessage returns zero
*    jnz mloop
********************************************************************************************

rest of modified pump
????????????????????????????????????????????????

WndProc proc hWin   :QWORD,
             uMsg   :QWORD,
             wParam :QWORD,
             lParam :QWORD

          cmp uMsg, 1023      ; don't process messages about 1023
       jg @F
   
          mov rax, uMsg
               mov rcx,  hWin
               mov rdx, uMsg
               mov r8, wParam
               mov r9,  lParam               
          call QWORD PTR [wMsgs+rax*8] ;use array as jump table .. there are only 1K messages although a couple of WM_USER messages prob fall outside this]
@@
.....................   
???????????????????????????????????????????????
example procs

WM_COMMAND_EVENT proc  hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD

         .switch wParam

          .case 300  ; reset list box 
                     mov rcx, hList[0]           
                     mov rdx, LB_RESETCONTENT           
                     mov r8, 0
                     mov r9, 0
               call  SendMessage
                     mov rcx, hList[0]           
                     mov rdx,LB_SETHORIZONTALEXTENT         
                     mov r8, 14000
                     mov r9, 0
               call  SendMessage
             
          .case 301  ; calculate gcd
             call MakeEuclid demonstrate gcd
   ..............         
  .....
               mov rcx,hWin
               mov rdx,uMsg
               mov r8 , wParam
               mov r9,lParam
           call   DefWindowProc
WM_COMMAND_EVENT_end:
    ret
WM_COMMAND_EVENT endp
align 10h

DEF_MSG_HANDLER proc  hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD

               mov rcx,hWin
               mov rdx,uMsg
               mov r8 , wParam
               mov r9,lParam
           call   DefWindowProc
DEF_MSG_HANDLER_end:
    ret
DEF_MSG_HANDLER endp 

WM_SETFOCUS_EVENT  proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
       invoke MessageBox,hWin,ADDR szMessSetfocus,ADDR szMessTitle,MB_OK
              ; mov rcx,hWin
               ; mov rdx,HWND_TOP
               ; mov r8 , 0
               ; mov r9,0 
               ; mov rax,sWid
               ; mov [rsp+20h],rax
               ; mov rax,sHgt
               ; mov [rsp+28h],rax
               ; mov rax,SWP_SHOWWINDOW
               ; mov [rsp+30h],rax
               ; xor rax, rax ; not sure about this but think it has to be 16 aligned
               ; mov [rsp+38h],rax
           ; call  SetWindowPos    ; this would be equivalent to   invoke SetWindowPos,hWin,hWin_TOP,0,0,sWid,sHgt,SWP_SHOWWINDOW
                                       but i took it out and just let the window follow a standard path
               mov rcx,hWin
               mov rdx,uMsg
               mov r8 , wParam
               mov r9,lParam
           call   DefWindowProc
          xor rax, rax
WM_SETFOCUS_EVENT_end:   
     ret
WM_SETFOCUS_EVENT endp       

and so on
???????????????????????????????????????????????????????????????????????????????????????????????????
            end of snippets of program
???????????????????????????????????????????????????????????????????????????????????????????????????

now the traditional  message pump works fine

with the jump table look up version ....

i can no longer edit details in edit boxes ..[the cursor on placement throws a WM_COMMAND message .. as per note below ]



obviously tracing exactly what TranslateMessage is doing in this instance is not easy due to

1) the volume of paint, sizing, etc etc messages which it is handling unseen for the most part

2) i only know that the entry into the edit box is entering the pump with a WM_COMMAND [111]
   which sort of surprised me a little but dont really know why the edit fields are now uneditable
   [ not entirely true as you can paste into them !! a bit like on cmd.exe]  unless translate message
   is doing the something i want to know about   ... i also have a sneaky feeling that i might get into
   trouble with threading but thats for another time 

if you havent tried this DONT RESPOND with a load of questions as its pointless

i only want to know if anyones done it
i could post the whole program if no one has any idea but then i might as well sort it myself
... but im sure someone already knows the answer

regards
Mike B 

hutch--

Mike,

I did one somewhere over 20 years ago for a WndProc() which was simple enough as almost all messages are under 1000 and it was done with a lookup table. Every message in the WndProc() was pointed at the correct location in about 3 instructions and while it did work OK, you could not tell the difference.

jj2007

Quote from: hutch-- on December 23, 2020, 12:19:08 PMyou could not tell the difference

We had several threads about Switch ... Case ... Endswitch implemented as if else endif vs jump tables. The latter rarely have an advantage. Practically all Windows messages are very slow, so a few cycles more in if else endif are not significant.

mikeburr

great answers thanks ....
yes thanks Hutch
everything works as it should EXCEPT the edit where its as though id set ES_READONLY [which i havent ] and it was annoying me
the odd thing is that you can amend them by pasting into them .. delete chars using the delete on the keyboard so i was a bit bemused by it
all the other controls work as they shd .. ive got a list box which you can fill beyong the scroll limit and the scroll bars work ok etc etc .. all the buttons [which go through WM_COMMAND obviously are ok .. its so odd
but
i must say it doesnt seem quicker

which bears out what youve said JJ ...
.. ill not bother then ..
i was hoping to somehow speed up the loop so if anyones got any ideas [peek message cant be any quicker i wouldnt have thought either ????]
regards   mike b

hutch--

If you look at the architecture of a Windows UI, either 32 or 64 bit does not matter, the speed limit from a message loop feeding messages to a WndProc is determined by the OS which in turn is dependent on what the window is doing, moved, resized or receiving messages from another source and about the only way you can "hot it up" is by getting the WndProc processing of messages sent by the OS in the lowest number of instructions.

I see such endeavours as virtuous as you learn a lot about efficiency but with a normal UI app, you won't see any difference. There are other tasks where a lookup table of labels with the instruction count for branching to each label is only a few instructions will give some very good performance gains if done properly so no research work is ever wasted.

jj2007

Quote from: hutch-- on December 23, 2020, 03:05:45 PM... so no research work is ever wasted.

Amen, that's exactly the right spirit for an Assembly forum :bgrin:

Besides, Mike, it is important to realise what the message pump really does: most of the time nothing. If there is no user input, it just waits for some action. No need to speed up the waiting :cool:

mikeburr

thanks to you both and i can thoroughly endorse  the WISDOM with which youve replied .. i put a series of displays in the program .. and was thus able to sort of see events and gradually filter and count aspects of the window activity .. the bulk of it is in maintaining an accurate notion of the position of the cursor and similar relative to the client window area .. some surprises were that the WM_IME_.. messages figure at all  !! theyre quite important
[ i dont know why but i hadnt expected it] ..
in fact if you think its a good idea ill post the code [im not using quite the sytem everybodys prob using in that ive gone for a mash up of the stuff MIKL VERY KINDLY SENT ME AGES AGO [massive thanks MIKL ] and  yours HUTCH [ so massive thanks to you and your great work on this site enabling us to enjoy assembler ]
and the exe as its quite illuminating ..
also
the command messages come through with the handle of the window /child window in the low part of wParam and the "action" in the high part ... why this isnt being effected for the edit boxes ive yet to discover at the time of writing ..
but thanks for all your help
regards mike b

mikeburr

correction .. NOT handle in the low part of wParam .. the id  ..

mikeburr

i didnt reply very well but basically the "action" in the case of the edit child windows is EN_CHANGE and isnt being set   except when i paste etc into it .. hope that makes more sense
regards mike b

daydreamer

Quote from: hutch-- on December 23, 2020, 03:05:45 PM
If you look at the architecture of a Windows UI, either 32 or 64 bit does not matter, the speed limit from a message loop feeding messages to a WndProc is determined by the OS which in turn is dependent on what the window is doing, moved, resized or receiving messages from another source and about the only way you can "hot it up" is by getting the WndProc proc
subclassing WM_PAINT and mostly used messages faster?
subclassing uses a pointer to PROC that takes care of WM_PAINT,faster to change pointer to right PROC seldom(area changes) than to different drawing PROC's compared to WM_PAINT(ca 30 fps) with switch/case lvl -1 to 4 different invokes + checking a flag if to draw intro text?
but doesnt it becomes more .COM interface than jumptable?,having indirect jump and adress is changing to right PROC only when needed?

subclass WM_TIMER better when much code?

much mouse control message,I think I going to try mov lParam to X(word) and Y(word) simultanously,because I want to try SIMD moving coding
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

hutch--

Magnus,

You don't subclass Windows messages, a subclass is a technique to access the messages sent to a window that does not have a message loop of its own that can be directly accessed. A subclass is a trick to intercept the messages to a window of that type, (mainly a control), process what you need within the subclass then pass the procedure's address back to the OS for default processing.

If you want a particular message to have priority over ordinary default messages, you put it up near the top of your WndProc.

A timer is an OS provided technique that runs in its own thread that sends messages to your Wndproc at user defined intervals. They work OK for ordinary things but are too slow for high frame rate code and this is where you need to use a multi-media timer that can have a resolution down to 1ms but if you need faster again you start using spinlocks and high precision timers and this stuff starts to get complicated.

jj2007

Quote from: hutch-- on December 24, 2020, 07:03:56 PM
A timer is an OS provided technique that runs in its own thread that sends messages to your Wndproc

I had never thought about it that way, but it sounds very logical - thanks :thumbsup:

hutch--

You can actually make your own timer, create a thread, run a loop in it that uses intervals of your choice, slow stuff can use GetTickCount() while much faster stuff can use much higher speed techniques but you will probably run into a boundary of how fast you can send messages as they get passed through the OS.

daydreamer

Quote from: hutch-- on December 24, 2020, 07:03:56 PM
You don't subclass Windows messages, a subclass is a technique to access the messages sent to a window that does not have a message loop of its own that can be directly accessed. A subclass is a trick to intercept the messages to a window of that type, (mainly a control), process what you need within the subclass then pass the procedure's address back to the OS for default processing.

I want to try a third way,used .COM interface alot earlier with ddraw,d3d,so replacing lots of switch/case to call different area drawing PROC's in WM_PAINT,with a single indirect jmp to current PROC and seldom decision change code of areas moved elsewhere and only changes pointer to different PROC,so is all you need some LOCK prefix for mov that changes jmp adresses,to not crash?
look at current code and its adding new areas all the time


.IF introflag==0
    switch lvl
    case -1
    call road ;on the road to different places
    case 0
   ; call paint2
    call labdraw0 ;ground lvl
    case 1
    ;call paint2
    call labdraw
    case 2
    call labdraw2
    case 4
    call queen
    endsw
   
    .ENDIF
    .IF introflag!=0
    call intro
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

tenkey

Quote from: mikeburr on December 23, 2020, 01:56:00 PM
everything works as it should EXCEPT the edit where its as though id set ES_READONLY [which i havent ] and it was annoying me
Your message pump doesn't call TranslateMessage. That's needed to create the WM_CHAR messages needed by EDIT controls for character input.