WinAPI progress bar: stop animation? - winapi

Is it possible to stop / suppress the "pulsing" animation of the progress bar?
(That was introduced with the vista themes IIRC)
We have a process that can be paused by the user (to inspect hardware or intermediate results). While there's the usual "Pause button pressed" feedback to convey the state, the progress bar animation makes it look like the process is still running.
(The easy way out - to hide the progress bar - would be suboptimal, as even in paused state the progress is somewhat relevant.)

Since you're using the progress bar introduced with the Vista version of the common controls library, you can do even better than simply suppressing the animation.
The progress bar has three states:
Normal
Paused
Error
You switch between the states by sending the progress bar control window a PBM_SETSTATE message. The wParam parameter should be either PBST_NORMAL, PBST_PAUSED, or PBST_ERROR. The lParam parameter should be 0.
The pulsing animation is suppressed for both the paused and error states.
To retrieve the current state of the progress bar, send a PBM_GETSTATE message.

It isn't very clear from the question, but it sounds like you display the progress bar in marquee mode. The "I'm not dead, don't know how long it will take but working on it" mode. Enabled by turning on the PBS_MARQUEE style flag.
You have control over the animation with the PBM_SETMARQUEE message. Allowing you to turn it off completely or by significantly increasing the animation time so it starts to just crawl. Somewhat appropriate perhaps for a "paused" mode. The default is 30 msec, it will look pretty crawly at 1000 msec. Completely freezing it is not an option, but no user will stare at it for INT_MAX msec.

Related

Is it possible in wxwidgets to determine if the window is currently visible?

In my wxWidgets (wxPython) app, I am using a 50 ms timer to do some polling and update a window if there are any changes. If changes are detected it calls wxWindow.Refresh to update the window, and the actual updating of the widgets is done in the EVT_PAINT handler. It would be nice if I could disable the painting and/or the timer if the user is not looking at the window anyway. However EVT_PAINT is still being fired even if the window is iconized or hidden behind a different window.
Is there any way to detect if the window is not currently visible on screen, or to prevent EVT_PAINT events from firing unnecessarily?
There is the IsActive method and the EVT_ACTIVATE event to test whether the window has focus, but I want to keep updating the window if it is unfocussed but still visible. The wxWindow.IsShown family of functions doesn't help, they still return True for hidden/iconized windows.
IsShownOnScreen() could help with the iconized case. Edit: But actually does not.
Or you could trap wxEVT_ICONIZE to detect when the window is minimized.
But to be honest I'm rather surprised that refreshing a window hidden behind another one still results in a repaint. If the window in front is not transparent, this really shouldn't happen.

MFC app doesn't seem to receive input messages?

We have a MFC Visual-C++ application that is not reacting to any user input.
(Note: Currently only known on one machine. The behavior does recur occasionally, but only after the App has been running for several days!)
The application is redrawn when we switch to it via Alt-Tab (or the Task Bar), but we cannot, for example, activate it's main window by clicking on the title bar.
We have already pulled 4 dumps with WinDbg and checked the active instructions. We always were in some redraw code or somesuch inside the main thread (the GUI thread). We definitely were/are not in a modal message loop and the main thread's stack always looked "OK". (Most/all worker threads were idling, waiting for some event, no suspicious code there either.)
When investigating the problem with Spy++, we see the behavior specified also in this separate question, namely that we seem to get paint and activation messages, but no user input is routed to the application. When I have the application window on the screen, and select it to show messages of the main window,
it will only show "generic" "referesh" messages and nothing else
If I drill deeper, and select all messages for the whole process,
this is what we see:
The app is apparently only processing messages on one hidden sub-window (00CB09F0), and what we see there is a constant stream of 200 WM_PAINT messages per second.
Normally this Sub Window isn't processing any messages at all (except refresh WM_PAINT etc. when Windows sends them). It is normally used as a drawing area and the drawing happens through a WM_TIMER message on it's parent (010A09B8) window. (This WM_TIMER message isn't shown on the hanging app either though.)
The performance profile as shown in process explorer looks like this (100% kernel time, more or less):
I'd say that you have a redraw loop in that window that receives the WM_PAINT flood.
That usually happens if you call Invalidate or similar from the processing of the WM_PAINT message, directly or indirectly.
Other posibility is that, since you say that you are using a timer to redraw the window, the actual drawing is taking more time that the time it self, so the messages pile up in the queue.
Yet another posibility is that you are invalidating the window from a different thread than the one making the painting.
Anyway, you should ensure that you are calling Invalidate*() properly (you showed no code), and never from the OnPaint event. And avoid calling UpdateWindow() as this function can mess things if called without a little care.
I've seen this problem when an exception is thrown from a dialog. MFC's DoModal function disables the main program window then reenables it when the dialog returns; exceptions bypass the reenabling part and the main window remains disabled forever.

On Windows, should my child window get a WM_WINDOWPOSCHANGED when its z-order changes relative to one of its siblings?

I am trying to insert a custom widget into the Internet Explorer 8 url bar, next to the stop and reload buttons. This is just a personal productivity enhancer for myself.
The "window model" for this part of the IE frame is an "address bar root" window that owns the windows which comprise the IE8 url bar: an edit box, a combo control, and the stop and reload buttons.
From another process, I create a new WS_CHILD window (with a custom class name) that is parented by IE's address bar root window, thus making it a sibling of the edit box and stop/reload. I call SetWindowPos with an hwndInsertAfter of HWND_TOP to make sure it appears "above" (i.e. "in") the urlbar. This works nicely, and I see my window painted initially inside the IE urlbar.
However, when I activate the IE window, the urlbar edit control jumps back in front of my window. I know this is happening because I still see my window painted behind the urlbar, and because when I print ->GetTopWindow() to the debug console on a timer, it becomes the HWND of the urlbar edit control.
If I update my message loop to call SetWindowPos with HWND_TOP on WM_PAINT, things are better -- now when I activate the IE window and move it around, my control properly stays planted above the edit control in the urlbar. However, as soon as I switch between IE tabs, which updates the text of IE's urlbar Edit control, my control shift backs behind the Edit control. (Note: This also happens when I maximize or restore the window.)
So my questions are:
1) Is it likely that IE is intentionally putting its urlbar edit control back on top of the z-order every time you click on a tab in IE, or is there a gap in my understanding of how Windows painting and z-ordering works? My understanding is that once you specify z-ordering of child windows (which are not manipulable by the end-user), that ordering should remain until programmatically changed. So even though IE is repainting its Edit control upon tab selection whereas I am not repainting or otherwise acting upon my window, my window should stil remain firmly on top.
2) Given that the z-order of my window is apparently changing, shouldn't it receive a WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED? If it did, I could at least respond to that event and keep myself on top of the Edit control. But even though I can see my window painting behind the urlbar Edit control when I click on a tab, and even though my debug window output confirms that the address bar root's GetTopWindow() becomes the HWND of the Edit control when I click on a tab, and even though I see WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED being sent to the Edit control with an hwndInsertAfter of HWND_TOP when I click on a tab, my own window receives no messages whatsoever that would allow me to keep the z-order constant. This seems wrong to me, and addressing it would force me to run in IE's process and hook all messages sent to its Edit control just to have an event to respond to :(
Thank you for your help!
It's quite likely that IE is juggling the Z-order of the controls when you change tabs. In IE9, the URL bar and the tabs have a common parent. When you select a new tab, it activates the URL bar (and activation usually brings the window to the top of its local Z order).
No. You get WM_WINDOWPOSCHANGED when a SetWindowPos function acts on your window. If some of the siblings have their z-orders changed, you don't get a message. Nobody called SetWindowPos on your window. You can see this by writing a test program that juggles the z-order of some child windows.
This makes sense because there might be an arbitrary number of sibling windows, and it could be an unbounded amount of overhead to notify all of them. It also would be nearly impossible to come up with a consistent set of rules for delivering these messages to all the siblings given that some of the siblings could react by further shuffling the z-order. Do the siblings that haven't yet received the first notification now have two pending notifications? Do they get posted or dispatched immediately? What if the queue grows and grows until it overflows?
This is different from WM_KILLFOCUS/WM_SETFOCUS notifications in that it affects, at most, two windows. That puts a reasonable bound on the number of notifications. Even if there's a runaway infinite loop because the losing control tries to steal the focus back, the queue won't overflow because there's only one SetFocus call for each WM_KILLFOCUS delivered.
Also, it's reasonable that windows might need to react to a loss of focus. It's much less likely that window C needs to know that B is now on top of A instead of the other way around, so why design the system to send a jillion unnecessary messages?
Hacking the UI of apps you don't control and that don't have well-defined APIs for doing the types of things you want to do is anywhere from hard to impossible, and it's always fragile. Groups that put out toolbars and browser customizations employee more people than you might expect, and they spend much of their day probing with Spy++ and experimenting. It is by nature hacking.

Continuous Progress Bar

Using VB6
I want to show the continuous progress bar during the code running time.
Progress bar continuously should run. Once the coding process is completed, the progress should be invisible.
How to make a code for the continuous progress bar
Need VB6 code Help
This is tricky to do if you have continuously running code, since VB6 is single threaded.
I've tried doing this myself (setting the width of a label control with a coloured background), but the GUI tends not to re-draw. I ended up dividing the work up into sections and calling DoEvents at the end of each section. The GUI update was rather coarse.
There are ways of running multiple threads in VB6 - but they need very careful handling - and from there you might be able to run code in one thread and update a GUI in another.
Traditionally we used the Animation Control didn't we? I'm not sure but I think it runs on its own thread. Then there's the WebBrowser control which can be used "chromeless" displaying an animated GIF.
Even Windows Movie Maker can be used to convert an animated GIF to an AVI though it might have limitations in that regard. Seems like you could easily make a barber pole, "Cylon's Eye," column of falling pixie dust, or any other "I'm busy" indicator you want if the Hourglass Cursor isn't good enough.
Cody Gray's marquee style ProgressBar was a great suggestion though.

Mouse pointer state in Windows applications doesn't change until mouse moves

Did anyone notice that in Windows applications the mouse pointer doesn't change from Hourglass back to normal until you move the mouse?
So even if your application has finished a task and the mouse pointer has been set to go back to default, it will stay as an hourglass until you move the mouse. What is the reason for this, and can be it resolved?
I'm not sure if other people have noticed this but it is quite strange and it might be some kind of event-driven way to conserve OS resources.
The dialog box should maintain the logic of the hourglass. The worker thread should send a message to the dialog itself, telling it to start maintaining an hourglass thread. (You could test this by adding a temporary button to the dialog which starts and stops the hourglass.)
Another thing to be aware of is that having a second process set the hourglass of the first is an odd thing to do. An hourglass should only happen due to user action. While an hourglass is up, typically the only action that should be available to the user is "Cancel [whatever operation is keeping the hourglass up]."
Can it be resolved? Call ShowCursor(FALSE) before you call SetCursor(), and ShowCursor(TRUE) afterwards. Should do the job.

Resources