Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28701 Discussions

Screen won't repaint after using Excel

michael_green
Beginner
1,818 Views
Hi all,
My application has a bitmap backgound and I use a series of dialogs for user input. One dialog shells out to an Excel template where some VB code ultimately writes a file before closing and returning to the dialog. At this point I'd like to see the dialog and its progress bar, but all I see is a white filled outline of it on a white background. The program still works OK and when it's done, the screen refreshes without my ever having seen the progress bar in action.
If I insert a pointless message box (click OK to continue) immediately on return from Excel, everything works just fine and I see the progress bar in operation.
What am I not doing that I should be doing?
With many thanks in advance,
Mike
0 Kudos
32 Replies
aliho
Beginner
514 Views
I notice that, during long tasks, Excel stops its message loop so no more repainting can occur until the end of the task.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
514 Views
Excel is a separate process, so its message loop can "drive" only itself, but not your program as well.

Mike, to get the screen updating while rtn_designtofmis is being executed, you have to do one of two things:

1) Insert a [do while PeekMessage...] loop into rtn_designtofmis code to be executed "frequently enough".

2) Launch rtn_designtofmis in a separate thread (CreateThread), then wait for it using MsgWaitForMultipleObjects as before. That requires no changes in dll source code. However, to pass arguments to the ThreadProc (which may have only one argument lpParameter), either make them global, or, better, pack them into a TYPE and pass its address:

type t_rtn_designparams
character(7) dbase
integer hProgress
...
end type t_rtn_designparams

type(t_rtn_designparams) rtnd
...
rtnd = t_rtn_designparams(dbase, hProgress)...
handles(1) = CreateThread(NULL, 0, LOC(ExecRtn), LOC(rtnd), 0, &
LOC(idThread))
do while(.true.)
iret = MsgWaitForMultipleObjects(...
...
end do
iret = CloseHandle(handles(1))

integer function ExecRtn(rtnd)
!DEC$ATTRIBUTES STDCALL:: ExecRtn
!DEC$ATTRIBUTES REFERENCE:: rtnd
type(t_rtn_designparams) rtnd

LoadLibrary(...
call rtn_designparams(rtnd%dbase, rtnd%)
ExecRtn = 0
end function ExecRtn


Jugoslav


P.S.1: You should call CloseHandle for PI%hProcess and PI%hThread when you're done with Excel.






P.S.2: After re-reading the docs, you need a do while (PeekMessage(...)) instead of if (PeekMessage(...)). As it is now, messages could be "eaten".




P.S.3: You're better off using ShellExecuteEx than CreateProcess if you want portability. On my computer, Excel.exe is not in PATH, so CreateProcess fails.






* (Actually, message loops operate on per-thread basis. However, even if you program a multi-threaded application, it's a good practice having only one GUI thread, i.e. with message loops and creation of windows. Doing otherwise is a good way to shoot yourself in the foot.)
0 Kudos
anthonyrichards
New Contributor III
514 Views

Michael,

The answer to your problem is to replace the 'pointless message box call'
with a WM_ERASEBKGND message to the progress bar:

!iret = MessageBox(ghwndMain,'Click OK to continue'C,'Pointless message'C, MB_OK)
iret=SendDlgItemMessage(Dlg%hWnd, IDC_PROGRESS, WM_ERASEBKGND,0,0)

please do not ask me why, it is a mystery!
regards
Tony Richards

0 Kudos
anthonyrichards
New Contributor III
514 Views
This is weird! It worked OK, several times - but now it doesn't!
I have just tried to build a release version, but it fails to find 'IDC_PROGRESS' keyword in the resource file. I note you use IDC_progress (i.e. lower case) and IDC_task. Have you modified the .RC file outside the resource editor? Resource.h and resource.fd contain the lower case versions. I wonder if this is part of the problem? I will reload your workspace from your zip file and see what happens....
0 Kudos
anthonyrichards
New Contributor III
514 Views

OK. Here is what happens on my system (CVF 6.6c, windows XP pro)...

With your unmodified code (except the full path to EXCEL is edited into the CreateProcess call), I press the 'Apply' dialog button and EXCEL starts.

IfI then press your EXCEL 'OK' BEFORE more than six or so seconds elapse, you get your number crunching and the progress bar updates ok!
I have repeated this over and over, it works every time, so long as you press 'OK' before a certain elapsed time.

If you wait any longer, and carefully watch your dialog window, you will see it
'flash' as itappears to beredrawn, but I find a small portion of it previously covered by my EXCEL window remains unredrawn and, guess what, when you then press your EXCEL 'OK' button, number crunching occurs but the progress bar FAIULS TO UPDATE. So it is partly a timing problem (it fails only after a certain elapsed time) and partly a consequence of what happens to your dialog window in that important flash when it appears to be updated.
Hope this helps!

0 Kudos
anthonyrichards
New Contributor III
514 Views
More information:Your UNMODIFIED code works perfectly, every time on a system using CVF 6.6c on windows 2000 Pro.
I have used the tool SPYXX.EXE (found, in my case,in /program files/ microsoft visual studio/common/tools/) to study the messages being sent to the progress bar window while the number crunchng is going on. I find that on Windows XP, you get a continuous series of PBM_SETPOS messages, whichshould beused to set the progress bar position, but the bar positionfails to be updated. HOWEVER, on the WIndows 2000 system,the progress bar window alsoreceives a series of PBM_SETPOS messages BUT, each is accompanied by a WM_PAINT message!
Might it therefore be worth trying a modification to your numbercrunching code that sends the PBM_SETPOS messages to the progress bar to preced/follow it with a WM_PAINT , 0,0 message each time and see what happens?
0 Kudos
michael_green
Beginner
514 Views

Hi Guys,

Thanks for all your help and many suggestions. I really have got the problem fixed this time.

Anthony, I tried many of your suggestions (one or two before you'd made them) and found the same type of "weird" inconsistent behaviour. I also found that timing was very important, which is why in an earlier post I stated that the problem was solved. It turned out that it was only solved when I went through the program quickly - a totally unrealistic situation.

Jugoslav's solution is the one that works - I am now running the number cruncher DLL in a separate thread and it works like a charm every time. I've learnt heaps throughout this process and now understand a little about separate threads, etc, where I knew nothing about them before.

Thanks again to everyone.

Mike

0 Kudos
anthonyrichards
New Contributor III
514 Views
A final query: what version of Windows are you running? The non-appearance (or non-execution) of WM_PAINT messages with each PBM_SETPOS under Win XP Pro as opposed to their appearance and execution under Win 200 Pro still requires explanation...
0 Kudos
michael_green
Beginner
514 Views

Anthony,

I'm using Windows XP and CVF 6.6. I guess I could (and perhaps should) have spent a lot more time investigating such subtleties but I'm under some pressure just to get the thing working so that I can move on to other things. Now that I've got the basic technique I have to extend and apply it to a number of similar cases, so I've still got lots to do.

Many thanks again,

Mike

0 Kudos
Jugoslav_Dujic
Valued Contributor II
514 Views
Probably, progress bars are implemented differently in 2000 and XP: as suggested by Tony's experiment, the former paint themselves on WM_ERASEBKGND, and the latter on WM_PAINT (WM_ERASEBKGND immediately precedes WM_PAINT). I don't know why, perhaps to enable support for new XP Themes ("skins"). In any case, the out result is supposed to be the same and the programmer should not care.

My point is, SendMessage(WM_ERASEBKGND) and SendMessage(WM_PAINT) are undocumented ways to achieve updating; as you discovered by "reverse-engineering", they're not reliable. Actually, I've never seen anywhere that direct sending of these two messages is a recommended way to do something; instead, you're supposed to pump these redrawing messages via a message loop of some kind.

Jugoslav
0 Kudos
anthonyrichards
New Contributor III
514 Views
The Msoft knowledge-base articles for WM_PAINT usually say that WM_PAINT is only processed when there are no other messages in themessagequeue. This is not much help if you want a progress bar to update on receipt of a series of new contents. I have seen statements in the same articles that say that UpDateWindow is the way to go if you want immediate response. It would be interesting to know exactly whichmessages Michael's number crunching DLL sends to the progress bar and if UpdateWindow gives consistent results across window versions....
0 Kudos
Jugoslav_Dujic
Valued Contributor II
514 Views
The Msoft knowledge-base articles for WM_PAINT usually say that WM_PAINT is only processed when there are no other messages in the message queue.



True, but that's usually not the problem (unless there's a very heavy message traffic accompanied by long processing code). However, in Mike's case, even if the message queue were empty otherwise, WM_PAINT could not be processed because no message can be processed while calculation is running. There's only one thread, remember.



I have seen statements in the same articles that say that UpDateWindow is the way to go if you want immediate response.



I tried InvalidateRect+UpdateWindow instead of PeekMessage loop in another example of mine (inspired by this very thread) and it does work, but it's not good enough. While user sits still, the progress bar gets updated, but e.g. Alt+Tab does not work anymore as expected -- the WM_ACTIVATE(APP) messages are not handled so the window can't put itself foreground until calculation is finished.



Jugoslav

Message Edited by JugoslavDujic on 10-07-2005 10:54 AM

0 Kudos
Reply