Modal window from within message handler in WTL/Winapi - c++

I have a small application that has a message only WTL window which does the background processing. But under some circumstances I would like to show a window that should behave as modal, that is, the message handler of message only window should not return until the user has clicked the button.
I was thinking that I could do it like this (pseudocode):
LRESULT OnMessageWndHandler1(...)
{
CModalWindow wnd;
wnd.create(...)
while(GetMessageLoop){}
}
But when I try, the window is created just fine, but pressing a key outputs tens of characters in modal windows editbox, not a single one like in regular window.
Most likely I'm doing something wrong, but I don't know what and what should be the correct approach. The modal window is completely code generated.

I would like to show a window that
should behave as modal ...
In my Unusual but Useful Dialog-based Classes Designed for Specialization you will find the way to call DoModal() on any control or homemade window.

It was probably a bad idea in the first place. The code is just the regular message loop. I decided to resort to less exotic solution.

Related

Using a dialog box as a main window. Not receiving WM_INITDIALOG messages

I have created a modeless dialog as a main window, but the window procedure isn't being sent WM_INITDIALOG messages.
Here's what I've done.
Created a dialog template using Visual Studio's resource editor, and
set its class name to a custom class.
Used WNDCLASSEX to register the class, window procedure, as well as
some icons and brush etc.
Used CreateDialog() with the last two parameters set to NULL, (Parent
window, and window procedure).
Created the message loop using IsDialogMessage(), TranslateMessage()
and DispatchMessage();
Returned DefDlgProc() in the window procedure as the default if no
messages were processed.
I can't think of anything else significant. Everything works well except for not receiving WM_INITDIALOG messages.
I've done it this way so the app minimises to the task bar, and I can have a menu if needed.
So my first question is, Have I done anything stupid?
Secondly, should I expect to receive WM_INITDIALOG messages using this system?
And if not, what is a good way to initialise say a combobox with strings.
(I've looked at things like WM_ACTIVATE, WM_ACTIVATEAPP etc, but nothing seems appropriate.
And the combobox isn't created yet at WM_CREATE.)
Thanks in advance.
I realised the answer shortly after posting.
As mentioned in the comments above, it's a window procedure, not a dialog procedure, so I shouldn't have been trying to initialize child windows within the procedure.
So I initialized them outside the procedure, after creating the dialog box and before the message loop.
All the dialog features are working as expected, but it's a main window that can have a menu and minimizes to the taskbar.

Radio button does not redraw correctly

Fig1:
Fig2:
As in Fig1, after I clicked radio button, the radio button seems not get correctly painted, seems 50% transparent.
As in Fig2, after I move my mouse to hover the radio button again, it got correctly painted.
I have no idea about what is going on behind.
What are the possible reasons?
By the way, after I pressed a shortcut key PrtSc to get a screenshot(a freeware: Greeshot), this problem disappeared.
One hint I just found is: the dialog holding the radios were in modeless mode. The problem disappeared after I showed it as a modal dialog.
Actually, to achieve below goals, I am implementing the message pump for this dialog. Perhaps I am doing something wrong in the message pump logic. Continue to check the pump.
My Goal: user can interact with other windows while showing this dialog, one exception is: user should not be able to interact with the parent dialog of this dialog in question, so that database transaction may be issued prematurally.
I used to have a similar problem within wxWidgets. Turns out it's a long lasting bug that really never had been fixed. I now use a workaround with a simple wrapper function that 'enables' the element (places focus on it) and then 'unfocuses' it. Not sure in your current setup.
As a result, it seems I did something wrong in the message pump for the dialog in question.
I am implementing the message pump for this dialog.
To avoid user interact with the parent dialog of the dialog in question, I was ignoring message for the parent dialog and to children of parent dialog.
After I changed the above logic to below, the problem got solved.
EnableWindow(hParent, FALSE);
EnableWindow(hParent, TRUE);
So, I think I was doing something wrong in ignoring message, not sure exactly where.

Setting focus to the parent window in the OnShowWindow of the child window doesn't work

Generally I have some button that opens child window and the second press on this button should close it. I use a touch screen.
The problem is when I try to press the button for closing the child window, it is not pressed the first time, so I need another click.
In order to fix this I am trying to return the focus to the parent window after the child window is opened.
I register the OnShowWindow message and call SetFocus on the parent window:
void CFlashGuidanceSteps::OnShowWindow(BOOL bShow, UINT nStatus)
{
CDialog::OnShowWindow(bShow, nStatus);
GetParent()->SetFocus();
}
While the function is called (I can see it in debugger), the focus is not returned to the parent window.
However, it works with the OnSetFocus event:
void CFlashGuidanceSteps::OnSetFocus(CWnd* pOldWnd)
{
CDialog::OnSetFocus(pOldWnd);
GetParent()->SetFocus();
}
Why is the focus is not retained with the OnShowWindow event?
The explanation
The usual rule in MFC is that OnXxx functions are called in response to similarly named window messages, e.g. WM_Xxx. So OnShowWindow would be called in response to WM_SHOWWINDOW.
And according to the documentation, WM_SHOWWINDOW is
Sent to a window when the window is about to be hidden or shown.
That means it is sent before the window is actually shown. So when you set the focus to the parent window inside of the OnShowWindow function, nothing actually happens because the parent window already has the focus. Then, after OnShowWindow finishes running, the child window is displayed and demands the focus. It is as if you never made any attempt to change the focus.
By contrast, OnSetFocus, which corresponds to WM_SETFOCUS, is not called until after the window has gained the focus. So when you reassign the focus here, it works because the child window doesn't steal the focus back.
The better idea
That explains the behavior you are seeing, and as you know, things work fine when you adjust the focus in OnSetFocus. But this really isn't the best way of solving the problem.
Manually changing the focus when a window gets and/or loses the focus is approaching the problem the wrong way around, and generally error-prone. You'll get all kinds of focus-related bugs that are difficult to debug. You are better off looking for ways to prevent the focus from changing when you don't want it to.
It sounds to me like you want to prevent the child window from getting the focus when it is created. And there is a way to do precisely that.
When you display the child window, presumably by calling the ShowWindow function or its moral equivalent in MFC, you should pass the SW_SHOWNA flag. That causes the window to be shown without activating it (i.e., granting it the focus).

MFC modal dialog close error

I have a strange error and spend hours in the debugger without finding a solution.
(But it helped me to fixed another error that you should never call EndDialog from a WM_KICKIDLE task).
My problem is that i have a main window and a modeless dialog window wich raises a modal subdialog window. When the subdialog window is closed. The modeless dialog window turns itself into a modal window. My code really does leave the modal loop. And if i close the now modal window it behaves like an invisble modal window is active, meaning no interaction is possible anymore.
When i only run a modal dialog on top of the main window it is closed fine.
BTW: The main window is not the one available view CWinApp::m_pMainWnd but a new create FrameWindow. I hide the p_MainWnd and use it as an invisible message only window. From some comments and my debugging session i found that the pMainWnd has some special meaning but i could figure what exactly it has to do with modal windows (there is an undocumented "CWinApp::DoEnableModeless" for example).
EDIT: I'm posting a WM_CLOSE to the dialog and then use EndDialog(0) from the OnClose() handler to exit the modal state. I also tried to use EndDialog(0) directly. There is no difference between this two methods.
When MFC creates a modal dialog, it makes it modal by disabling the windows above it. The code that reenables those windows occurs when the dialog ends normally with a call to EndDialog. If anything prevents that code from running, the other windows will be locked out.
Modeless dialogs are a different beast, and there's a note specifically in the EndDialog documentation warning you to use DestroyWindow instead.
Maybe this is justifiable but I have a question:
why are you using hidden window? Was it created as message only window (passing HWND_MESSAGE as a parent handle and Message as a class) or you just call it message only?
OK, a little more info about MFC and dialogs.
MFC does not use Windows modal dialog. It always creates modeless dialog; either Create or DoModal call in turn ::CreateDlgIndirect windows API.
Modeless dialof rely on the main window message dispatch, while modal calls RunModalLoop that is similar to MFC window message pupmp (not a message loop).
It runs in the main thread of execussion without freezing because it allows for idle processing (calls OnIdle).
How do you dismiss the modeless dialog? As Mark pointed you should use DestroyWindow.
As for m_pMainWnd, MFC framework uses it extensively to determine may things that control main window behavior. By changing it you may have created the behavior you experience.
Did you set the value to a newly created frame you treat as a main window?
What kind of MFC application is it? SDI or MDI?
Would it be possible to create test app to duplicate this behavior and post it somewhere for download?
By the way, you do not have to be concern about DoEnableModeless, since it does not do anything but calls hook (COleFrameHook type) that is spasly used, unless you are trying to implement some functionality using OLE or ActiveX or you are trying to marry MFC and .NET Windows Forms.
In conclusion if your (or third party code uses this hook, I would suggest checking the code in the COleFrameHook class.

Getting title bar double-clicks

I am working on a MFC C++ application. I was working on a dialog that has SystemMenu property set to FALSE, so it does not have the ability to maximize. I want to handle the double-click message on the title bar. How can I do that?
EDIT:
I hope this time it will be clear for everybody. I have a dialog that does not have system menu (and system buttons or icon). When the user double-clicks the titlebar of that dialog, I want the program to call function x();.
Technically, you would have to handle WM_NCLBUTTONDBLCLK and check if the double click occurred in the caption area of the window, possibly by sending it WM_NCHITTEST and testing that the return value is HTCAPTION.
(Update: As JohnCz rightfully points out, sending WM_NCHITTESTis not actually necessary, since WM_NCLBUTTONDBLCLK already carries its result in wParam.)
Then you would only have to send WM_SYSCOMMAND with SC_MAXIMIZE in wParam to the window to maximize it.
In practice, however, it will not achieve much if your dialog box is not ready to handle size changes and layout its controls accordingly. This feature did not come out of the box in MFC last time I checked.
I think there is some kind of confusion here:
Frédéric Hamidi
You are correct, handling WM_NCLBUTTONDBLCLK message is the right way to go, however it is no necessary to call HitTest, since WM_NCLBUTTONDBLCLK message delivers hit information that MFC framework translates in the WM_NCLBUTTONDBLCLK handler.
Victor,
What is exactly that you are trying to achieve by handling WM_NCLBUTTONDBLCLK message?
Maybe there is some other way to fulfill your requirement once you make it clear to us.
The fact that you do not have system menu, does not prevent your app from receiving non-client area messages.