MFC - WindowsCE - CWaitCursor - c++

I have created a dialog that runs on the main thread of an MFC application. While this dialog is made modal, it does a few things on the main thread (i.e message pump thread) that takes time. Whenever something takes time, I create an automatic variable using the MFC class CWaitCursor.
While in the OnInitDialog method, it works as intended. However, If I do the same past the end of OnInitDialog, like for example in a method called in response to a custom Window Message, the the wait cursor doesn't show up. However, if I "activate the application" using EveryWAN (which is a remote control application allowing to see and control the device from the PC), then the cursor DOES show up.
I could provide the code, but it's filled with a lot of stuff that is unlikely to be related to the problem. I'll just write an example code instead that shows what I just tried to explain :
class MyDialog : public CDialog
{
public:
BOOL OnInitDialog()
{
CWaitCusor oWaitCursor; // Shows wait cursor.
Sleep( 5000 );
PostMessage( WM_FOO, 0, 0 );
}
LRESULT OnFoo( WPARAM wParam, LPARAM lParam )
{
CWaitCusor oWaitCursor; // Does NOT show wait cursor, unless I "activate" the application...
Sleep( 5000 );
}
};
Do you have an idea of what could cause the wait cursor not to show up past InInitDialog ? Is it a Windows CE bug ? Is it a focus, screen refresh or a z-index problem ? Thank you.

Related

WinAPI timer callback not called while child window is in focus

I'm working on a 3D editor app using Direct3D and WinAPI. I create a main window, which has a child window that takes up a portion of the main window's client area. This is used by D3D as the render target. I then also create a separate window with CreateWindow, which is built the same way as the main window (i.e a "main window" and an internal child used as a render target), and I make this window a child of the main application window (to ensure that they are minimized/restored/closed together).
The D3D rendering is executed by the render target child windows processing their WM_PAINT messages. To reduce unnecessary overhead, I set the window procedures to only render on WM_PAINT if GetForegroundWindow and GetFocus match the respective window handles. In other words, I only want a window's rendering to be refreshed if it's on top and is focused.
This is my main message loop:
HWND mainWnd;
HWND mainRenderWnd;
HWND childWnd;
HWND childRenderWnd;
// ...
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(mainWnd, accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// Run non-UI code...
}
}
When the main window gets WM_SETFOCUS, I have it set the focus to its render target child window, since I'll want to process inputs there (e.g camera controls):
// ...
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
//...
case WM_SETFOCUS:
{
SetFocus(mainRenderWnd);
return 0;
}
//...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
I do the same in the window procedure for childWnd, setting the focus to childRenderWnd. This window is opened and closed by the user, i.e at any one time it may or may not exist, but when it does and is not minimized, it needs to be the foreground window with focus. Also, to control the framerate for the child window, I use a Timer to refresh it:
static constexpr UINT_PTR RENDER_TIMER_ID = (UINT_PTR)0x200;
void TimerCallback(HWND Arg1, UINT Arg2, UINT_PTR Arg3, DWORD Arg4)
{
if (IsIconic(childWnd) || !(GetFocus() == childRenderWnd))
return;
// Invalidate the render area to make sure it gets redrawn
InvalidateRect(childRenderWnd, nullptr, false);
}
// ...
SetTimer(childWnd, RENDER_TIMER_ID, 16, (TIMERPROC)TimerCallback);
With all this set up, mainWnd and mainRenderWnd seem to work just fine. However, childRenderWnd refuses to have anything rendered to it when it is in the foreground and in focus. While debugging, I found that while this is the case, the timer callback never gets executed, nor does a WM_TIMER message get dispatched to the child window.
On the other hand, the moment I deliberately move focus out of the child window and onto the main window (while keeping both open), the timer message gets sent, and the callback is executed. Another problem is that when I minimize the app while both windows are open, and then restore them both, the render target of neither of the windows is refreshed. Instead, it seems like the focus got "flipped", as I have to click on my child window first, then my main window, and that makes it refresh properly (while the child still refuses to render anything).
What am I missing? I searched for others having problem, e.g an incorrect message pump setup blocking WM_TIMER, but nothing seems to explain what's going on here.
Thanks in advance for the help!
IInspectable and Raymond Chen's comments have helped lead me to the answer. I tried to reproduce the error in a minimal app and finally came upon the source of my trouble. Originally, the main window would just call InvalidateRect in the message loop if there were no messages to be dispatched, effectively redrawing itself every chance it got. This originally did not seem to cause any harm, the scene was rendered just fine, and the window responded to inputs. Once I introduced a second window, however, it must have flooded the message loop with paint messages, making it impossible for any timer messages to get through.
The solution, quite simply, was to give a timer to both windows to set the rate at which they would refresh their D3D render targets. Coupled with focus checks, I can now easily alternate between both windows, with only one refreshing itself at any given time.
The question remains whether the WinAPI timer system is the best choice. My bad code aside, people have mentioned that the timer's messages are low-priority, which might make it a poor choice for framerate control in the long run.
EDIT: I ended up going with IInspectable's suggestion to use a while loop within the main message loop to process to dispatch all messages, and once those are processed, I perform a frame update. This allows me to consistently update all windows and control the frame rate without risking the issue of window messages being stuck.

Prevent window movement

I currently have a small game which runs in a win32 window. I just noticed that when I hold the top of the window (the bar which has the closing button) it freezes my application. I would like to disable this as it manages to completely destroy my application (timers continue to count).
It seems that with even the most minimalistic settings for creation of the window it still has this feature. How can I disable this? I currently have:
HWND hWnd = CreateWindowW( L"Game",L"Game",
0x00000000L | 0x00080000L,
wr.left,
wr.top,
wr.right-wr.left,
wr.bottom-wr.top,
NULL,
NULL,
wc.hInstance,
NULL );
I read that my thread is ignored while dragging, if I am forced into using 2 threads could someone please provide a small example of usage?
Or should I stop the timers? (what message should I catch, and would it even be catched?)
Update
I am using instances of my time class to handle timings which looks something like:
Timer::Timer() {
__int64 frequency;
QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency );
invFreqMilli = 1.0f / (float)((double)frequency / 1000.0);
StartWatch();
}
void Timer::StartWatch() {
startCount = 0;
currentCount = 0;
watchStopped = false;
QueryPerformanceCounter( (LARGE_INTEGER*)&startCount );
}
My Win32 message loop contains: mousemove, keyup and keydown.
When DefWindowProc handles WM_SYSCOMMAND with either SC_MOVE or SC_SIZE in the wParam, it enters a loop until the user stops it by releasing the mouse button, or pressing either enter or escape. It does this because it allows the program to render both the client area (where your widgets or game or whatever is drawn) and the borders and caption area by handling WM_PAINT and WM_NCPAINT messages (you should still receive these events in your Window Procedure).
It works fine for normal Windows apps, which do most of their processing inside of their Window Procedure as a result of receiving messages. It only effects programs which do processing outside of the Window Procedure, such as games (which are usually fullscreen and not affected anyway).
However, there is a way around it: handle WM_SYSCOMMAND yourself, resize or move yourself. This requires a good deal of effort, but may prove to be worth it. Alternatively, you could use setjmp/longjmp to escape from the Window Procedure when WM_SIZING is sent, or Windows Fibers along the same lines; these are hackish solutions though.
I solved it (using the first method) this past weekend, if you're interested I have released the code to the public domain on sourceforge. Just make sure to read the README, especially the caveat section. Here it is: https://sourceforge.net/projects/win32loopl/
Since the title bar to the user that he/she can move the window, you could remove that title bar and borders altogether. See "opening a window that has no title bar with win32" for an example.
When the game launches or is paused, you could show your own UI elements to allow the user to move the game window in these specific situations but only then.
You can check for the size/move loop using the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages.

Programmatically closing a dialog box - win32

I'm working on an application to detect a pop-up dialog and then
automatically dismiss it. I'm writing this as a C++/Win32 app. The
dialog box is generated by IE 7 and I can detect the window, but
several methods to get the OK button to "click" have failed.
Doing searches for other people's solutions, sending these messages to
the button handle seems to have worked in a lot of situations:
PostMessage( handle, WM_LBUTTONDOWN, 0, 0 );
PostMessage( handle, WM_LBUTTONUP, 0, 0 );
PostMessage( handle, BM_SETSTATE, 1, 0 );
It has no effect on the button state in my tests though.
I can send tab characters to the main window and see that the OK
button gets focus, but then sending return characters does nothing.
To learn more about this I used Spy++ to get information about the
window hierarchy and what messages are delievered when I manually
click the OK button.
Looking at the message log and reading about WM_MOUSEACTIVATE seamed
to offer a solution. The log info shows that 0002166C was the button
window. So in my code I tried this:
GetClassNameA( handle, str, str_size );
if( strcmp( str, "Internet Explorer_Server" ) != 0 )
return TRUE; // Not the window we're interested in.
// Send a message to activate the button window and have it process a mouse click.
PostMessage( handle, WM_MOUSEACTIVATE, (WPARAM) dialog_handle, MAKELPARAM( HTCLIENT, WM_LBUTTONDOWN );
Based on the window hierarchy and message log, I think the window with
the class name "Internet Explorer_Server" is the button. Maybe I'm
wrong, because it does seem like an odd class name for a button...
Below is a link to the window hierarchy image, message log when I
manually click the OK button. Last is the code that's executed on a 1
second timer ticket, looking for the window.
Any insight and help is appreciated!
Image of the window hierarchy, source, window messages, and test dialog source are available here:
https://sites.google.com/site/matthewmillersmiscellanea/Home/
Ideally, you should create a DLL which exports a Global CBT Window Hook. This would allow you to get early notification when a dialog is going to be created. This would avoid the need to drain resources by constantly polling.
Once you've detected that a dialog is about to be created, you have two options:
1) Prevent the dialog creation.
I don't recommend this, it causes all sorts of problems with code that was fully expecting a valid HWND to be returned by CreateDialog();
2) Asynchronously control the dialog.
We achieved this by using PostMessage with a Registered user message and picking it up by hooking the WNDPROC. When you get this message, then you have to decide how to kill the dialog that you're in.
There are multiple ways to exit the dialog:
a) Simulate pressing OK, Cancel, Abort, No buttons using WM_COMMAND(BN_CLICKED) (as Chris comments). You can use GetDlgItem(), look for the WindowText and make your choice. However, this doesn't work for non-US-English. There may be some distance in leveraging the Accessibility API here though.
b) Simulate closing the dialog with PostMessage(WM_CLOSE, m_hWnd). This doesn't always work as expected - some dialogs have no [X] close button and their client code is expecting a specific button to be pressed instead.
c) Simulate user input using the SendInput() API. This worked around dialogs that had anti-popup-killer code in them :)
Our final solution was a rule+heuristic-based approach that had a configuration file which we could tweak when the app/IE dialogs changed their ID's, class names or parent class names.
To close continually a specific popup given that you know the window class name and window caption
#define UNICODE
#include <windows.h>
#pragma comment(lib, "user32")
int main (int nn, char ** aa)
{
while (true) {
HWND iHandle = FindWindow (L"theWindowClassName", L"theWindowCaption");
if (iHandle > 0) SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
Sleep (200); // check 5 times per second
}
return 0;
}
if one is not known or too generic (e.g. "Dialog") you can omit it by passing a null
HWND iHandle = FindWindow (L"theWindowClassName", 0);
or
HWND iHandle = FindWindow (0, L"theWindowCaption");
of course this will close all windows with the given names.

Is there any function called after the OnInitDialog function in MFC?

I want to create a thread after the creation of a dialog box in MFC. Is there any function that Windows has provided and is automatically called after OnInitDialog so that I can create my thread inside it?
You can simply create your thread in the OnInitDialog function. There's no reason to overcomplicate things by going and searching for a different function, or splitting your initialization code up in two pieces. (There also isn't any such function, because there's no corresponding Windows message that is sent.)
If you want to get your dialog box on the screen before you create the thread, you can just show it manually using the ShowWindow function. For example:
ShowWindow(SW_SHOW);
RedrawWindow();
Also see this post by Raymond Chen: Waiting until the dialog box is displayed before doing something
OnInitDialog() is the main function called upon initialization (in reaction to WM_CREATE).
Why can't you create your thread in there?
I have changed the thread priority to below normal and when the thread executes for the first time I set the thread to normal priory. This works fine. Thanks for your response.
After many years of feeling unsatisifed with the OnTimer solution to draw first view graphics in an MFC dialog app (a favorite playground), this seemed like a nice simple solution:-
Add a WM_HSCROLL handler with class wizard.
At the end of OnInitDialog post a hscroll message with a NULL LPARAM
In handler detect the NULL, draw graphics.
a timer meant that the app was alive for some time before graphics happened, and apparently hscroll is prioritized to happen just after the WM_PAINT message which would erase a picture element to its blank state, deleting anything that was drawn during initdialog.
BOOL CSpecDlg::OnInitDialog()
{
...
PostMessage(WM_HSCROLL,0, (LPARAM)NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CSpecDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
if (pScrollBar==NULL)
{
plot();
}
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

Using modal progress bar dialogs in Windows CE?

I'm writing a Windows CE application in C++ directly applying the WINAPI. In this application I parse a text file, which may or may not be large and thus may or may not take a while to load; and as I will add functionality to load files across the wireless network, I figured it would be best to add a progress bar.
My aim is to display the progress bar in a modal dialog, thereby preventing the user from interacting with the main window. A thread is then created to perform the loading in the background, leaving the main thread to update the GUI.
However, using EndDialog() prevents me to return to the code which loads the file until the dialog has been closed. Obviously I want to show the dialog and then load the load, periodically updating the progress from the background thread. At this point I only know of two options to circumvent this:
Create the dialog using CreateDialog, modify the message handler to accommodate messages designated to the dialog, disable the main window and lastly create the background thread.
Create the background thread in a suspended initial state, create the dialog using DialogBoxParam passing along the thread ID, and when capturing the WM_INITDIALOG resume the thread.
Although any of these two would probably work (I'm leaning towards the second option), I'm curious about whether this is the way progress bars are supposed to be handled in a Windows environment -- or if there is a leaner, more clever way of doing it.
You don't have to do anything particularly tricky or unusual. Just create the modal dialog box with DialogBox(). In the WM_INITDIALOG handler of your dialog box procedure, create the background thread to load the file. As the loading progresses, send the PBM_SETPOS message to the progress bar control to update it.
When the loading completes, call EndDialog() to close the dialog box. However, EndDialog() must be called from within your dialog procedure. So to do that, you need to send a dummy message (e.g. WM_APP):
DialogBox(..., DlgProc);
// File loading is done and dialog box is gone now
...
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, LPARAM lparam, WPARAM wparam)
{
switch(msg)
{
case WM_INITDIALOG:
CreateThread(..., LoadingThread, ...);
return TRUE;
case WM_APP:
EndDialog(hwnd);
return TRUE;
...
}
return FALSE:
}
DWORD WINAPI LoadingThread(LPVOID param)
{
// Load the file
while(!done)
{
...
SendMessage(hwndProgressBar, PBM_SETPOS, progress, 0);
}
SendMessage(hwndDialogBox, WM_APP, 0, 0);
return 0;
}