News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Tight Loop

Started by Jimg, January 14, 2005, 02:29:07 PM

Previous topic - Next topic

Jimg

Newbie question here.

I'm in a tight loop doing some lengthy computations, and I am updating an editbox every million loops to show the progress.  What is the command to refresh the editbox on the screen after I do the sendmessage wm_settext to the editbox?  Likewise, I have a quit button, but while in the loop, it never gets a chance to send me a message that it was pushed.  What is the normal procedure for refreshing the state of pushbuttons so I can service it in the main dialog proc?

Edited:
Ok, I found UpdateWindow for the edit box.  Is this the best one to use?

UpdateWindow didn't work for the quit button however.

jimh

Call InvalidateRect before you call UpdateWindow.


invoke InvalidateRect, hWnd, NULL, TRUE
invoke UpdateWindow, hWnd


Assuming "hWnd" represents the window handle of your edit window, then the first call adds its entire visible area to Windows' internal update region.  The call to UpdateWindow will then have something to do.

Jimg

#2
Thank you.   It was working but only every 10th time without the invalidaterect, I will know to use it in the future.  Any ideas on the quit button?

jimh

As for the button you'll have to find a way to process your application message loop.  The WM_COMMAND message generated by clicking the button won't get processed if you are constantly in a processing loop rather than the main message loop.

Many apps create a separate, fast "worker thread" which does your lengthy computations while the application thread continues to respond to message events.  The main thread won't respond as snappily as an app doing nothing except waiting for the user to click a button, but it will respond.  This would probably also partially fix your EDIT window update issue.

Jimg

Ok, Thanks again.

QuoteThe plural of "data" is "data" ---So saith the wise Alondo.

We argued for years about writing reports whether you say  "The data is ..." or "The data are ..."    :P

raymond

Using a separate thread for your lengthy computation is probably the better route to continue processing messages sent to your edit box. You can still post messages from your thread so that your edit box will set new text while your computation is still going on. You will still have to establish some means of communication between your thread and your main window.

If you are not yet familiar with threads, you will find an excellent detailed explanation at:
http://board.win32asmcommunity.net/viewtopic.php?t=17&highlight=thread

The other way to respond to messages sent to your main window while doing your computation without using a thread is to peek at the message loop at intervals and terminate/suspend the computation if necessary, returning control to the main window to process the message. This could be the easier way if the number of messages requiring immediate action are few.

Raymond

When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Jimg

Thanks for the clue, Raymond.  PeekMessage seems to be exactly what I was looking for!

MANT

Actually I believe data is the plural for datum. Latin, y'know! The "correct" usage for data is to treat it as plural: "the data are..."

However, I think that battle was lost long ago. Everyone treats "data" as a collective singular, like "debris": there's no such thing as one debris, yet we treat it as a singular in a sentence. At least in America we do. I'm not sure about the King's English. Here we say "the group is..." whereas in the UK, Oz, and NZ they say "the group are..."

Really rather a silly language at times. ::)

Bieb

When a group acts as a group, you would say is.  For instance, the group is going to the party.  But, if the members of the group are acting seperately, you use are.  At least in standard English.  No one talks that way.

MANT

Not separately, individually. This is a good page that explains it...

http://alt-usage-english.org/groupnames.html

Anyway, way off-topic, sorry! :toothy

Jimg

Ok, I've been playing with this for a couple of days.  I read up on threads, and while they will probably work, they seem unnecessarily complicated.  I tried peekmessage, but no luck.  The problem seems to be, even though I click on the quit button while in the tight loop, a message is never sent to the button so nothing for peekmessage to find.  I read up on Queued Messages in the win32.hlp file and it seems very straighfoward and simple, but it doesn't work for me.  The mouse moves over the button, so I know the system is working, it just that a message to the command button is never put in the queue.  I gave it plenty of time to catch up by exiting the procedure with the tight loop, but no message.  I know the button works because I get a message if I click on it outside the tight loop procedure.  The only thing I can think of is trying to catch the mouse messages, but before I enter that can of worms, I thought I would see if anyone else had any ideas.

raymond

Jimg

How about posting that piece of code in your tight loop where you tried to intercept the messages. We may be able to help you figure out your lack of success. PeekMessage should work when used properly.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Jimg

Ok, I'll strip out the crud and reconstruct what I tried and post it later tonight or tomorrow.  Thanks.

Jimg

This is embarrasing :red

I started from scratch, and peekmessage worked this time.  The problem before was I was trying to do too much, testing the lpMsg return of Peekmessage to see if the button was pushed, and I never got the WM_COMMAND message with BN_CLICKED for the button.

This time I just did the peekmessage followed by a dispatchmessage and let the main loop handle it and set a flag.  Seems to work great in this simple example.  Here's the code in case I'm doing something really dumb you'd like to point out  ;)

.486
.model flat, stdcall
option casemap :none
.nolist
include windows.inc
; -----------------------------------------------------------------------
literal MACRO quoted_text:VARARG
LOCAL local_text
.data
  local_text db quoted_text,0
.code
EXITM <local_text>
ENDM

SADD MACRO quoted_text:VARARG
EXITM <ADDR literal(quoted_text)>
ENDM
sadd equ SADD
GetHandle Macro MyId:Req,MyHandle:Req
    invoke GetDlgItem,hWin,MyId
    mov MyHandle,eax         ; save handle to control
endm
uselib MACRO libname
    include     libname.inc
    includelib  libname.lib
ENDM
; -----------------------------------------------------------------------
uselib user32
uselib kernel32
uselib shell32
.list

DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.data?
buf1 db 100 dup (?)
hWin dd ?
hEdt  dd ?
LoopCnt dd ?
.data
QuitPushed dd 0
Started dd 0
AllDone dd 0
.code
Program:
invoke GetModuleHandle,NULL
invoke DialogBoxParam,eax,101,0,ADDR DlgProc,0
invoke ExitProcess,eax

DlgProc proc uses edi esi ebx hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
    .if uMsg == WM_COMMAND
        mov eax,wParam
        mov edx,wParam
        shr edx,16
        .if ax==1001 ; doit button
            .If edx==BN_CLICKED
            call Doit ; go do test
           .EndIf
        .elseif ax==1003 ; quit button
            .If edx==BN_CLICKED
            inc QuitPushed ; flag that quit was pushed
.endif
       .endif
    .elseif uMsg== WM_INITDIALOG
    push hWnd
    pop  hWin
    invoke GetDlgItem,hWin,1002
    mov hEdt,eax         ; save handle to edit box
    .elseif uMsg == WM_CLOSE
        invoke EndDialog,hWnd,0
    .else
pass:   mov eax,FALSE
        ret
    .endif
    mov eax,TRUE
    ret
DlgProc endp

.data?
lpMsg MSG <?>
.code

Doit:
mov LoopCnt,1
Cnt:
invoke wsprintf,addr buf1,sadd(" doing loop %li"),LoopCnt
invoke SendMessage,hEdt,WM_SETTEXT,0,addr buf1
cmp QuitPushed,0
jne Done
mov ebx,1000000000 ; this takes about a second on my machine
again:
sub ebx,1 ; this represents my long calculation loop
jnz again
inc LoopCnt
PMsgLoop:
invoke PeekMessage,addr lpMsg,hWin,0,0,PM_REMOVE ; Check for a message
or eax,eax
je Cnt ; no message available
invoke DispatchMessage,addr lpMsg
jmp PMsgLoop
Done:
invoke MessageBox,hWin,sadd("Found quit flag inside doit, quitting!"),0,0
ret
End Program

; Here's the rc
#define Doit 1001
#define CurLoop 1002
#define Quit 1003

101 DIALOGEX 6,6,77,66
CAPTION "Test"
FONT 8,"MS Sans Serif"
STYLE 0x90cf0880
EXSTYLE 0x00000000
BEGIN
CONTROL "Doit",Doit,"Button",0x54002000,8,9,61,13,0x00000000
CONTROL "",CurLoop,"Edit",0x50010000,8,26,61,13,0x00000200
CONTROL "Quit",Quit,"Button",0x50010000,8,44,61,13,0x00000000
END



I'll put this in my real program and cry and moan some more if it doesn't work there.

raymond

It will work if you only click on the "Quit" button while your loop is running.

However, the way you have it set up may have unexpected consequences if you click on the "Doit" button.

- After the DispatchMessage, your loop waits until that function has terminated and returned before performing the next instruction.

- When the message is handled by your DlgProc, guess what happens: the Doit procedure would be called and started over again until completed, and control may then be returned to the point when the loop was interrupted by the click on that "Doit" button and the computation resumed from that point!!!

As your DlgProc gets more complex, you could have other surprises also, apart from delaying your loop for a lot of messages which may be of no importance to that loop (such as processing mouse movement messages which may be required to determine which values to use to start the loop)

The proper way of using the PeekMessage is to identify only those messages which require immediate termination of the loop. If the loop could be resumed later, you then save whichever data is required for such resumption and then return control to your DlgProc.

The following would be an example for your app to process only the Quit message.

PMsgLoop:
invoke PeekMessage,addr lpMsg,hWin,WM_COMMAND,WM_COMMAND,PM_REMOVE
or eax,eax
je Cnt
mov eax,lpMsg.wParam
cmp ax,1003
jnz PMsgLoop
invoke PostMessage,lpMsg.hwnd,lpMsg.message,lpMsg.wParam,lpMsg.lParam
ret


Your 1003 case in the DlgProc should thus be modified to quit the program instead of changing a memory variable.

The above could be expanded to also look for other messages such as the WM_CLOSE.

I guess this should be enough to get you started on the right track. Many, many more variations are possible.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com