Opening a window in other method than `DialogBox` - c++

I have a dialog IDD_WINDOW_INFO that has to be opened when the user clicks a button or a menu item in my C++ Win32 application. The method that I use to open the dialog is in the following line:
DialogBox(hInstance, MAKEINTRESOURCE(IDD_WINDOW_INFO), hMainWindow, WindowInfoProc);
but my problem is that when that dialog box opens, the user cannot operate with the main window of my application. So what can I do to have both windows active?

You are calling DialogBox which shows the dialog modally. When a modal dialog is shown, the other owning windows are disabled and only the modal dialog can accept input. That is the very essence and intent of a modal dialog. The idea is that you can interact only with the dialog, and cannot interact with the other windows.
Another answer suggests passing NULL as the hWndParent parameter to DialogBox. That's not the solution. That will result in you having an unowned window. Yes, you will be able to interact with the main window, but when you do so your main window will appear on top of the dialog. That's because the ownership is set incorrectly. I recommend that you read about window ownership to better understand the issue.
The correct solution to your problem is to show a modeless dialog. A modeless dialog allows you to interact with the other windows in your application. And that's exactly what you ask for in the question.
You show modeless dialogs by calling CreateDialog followed by ShowWindow. This MSDN article shows an example: Using Dialog Boxes.

If I recall correctly, you can either pass NULL instead of the handle to the parent window or change the dialogbox type in the resource editor.
That is an easy way to do it, however the following is certainly better - since having an unowned dialog isn't your best choice.
The point is that DialogBox() will create a modal dialog window, while CreateDialog does not. Modal dialogs disable the parent window.
From MSDN: A modeless dialog box neither disables the owner window nor sends messages to it.
That should solve your problem.
CreateDialog(hInstance, MAKEINTRESOURCE(IDD_WINDOW_INFO), hMainWindow, WindowInfoProc);
ShowWindow(hWnd, SW_SHOW);

Related

Can't focus from main window after closing dialog from other thread

I create a new CWindThread in CWinApp::InitInstance(). In that thread, I create a dialog (for displaying a progress bar in that dialog).
After finishing InitInstance(), I close the dialog by calling DestroyWindow() from the dialog, but the application is loosing focus from main window.
I used AfxGetMainWnd()->SetActiveWindow(); to set focus for main window but it is not working.
How can I return the focus to the main window after closing the dialog?
There is no real good way to do that. The focus is set per thread. So there is no "focus" over all windows.
The only chance you have is to set the new foreground window, that belongs to the other thread with SetForegorundWindow. From within the same application this should work without restrictions.
If it doesn't work you need to "synch" both message queues. This is done by AttachThreadInput. If both messages queue are already attached, than there is no problem with settings the focus directly. But the behaviour of the application will change... Please read the docs, of the functions I linked too.
When a modal popup window is displayed, the reason a user cannot interact with the owner window is that it is disabled. When the modal window is destroyed, care must be taken to re-enable the owner window BEFORE destroying the popup as windows cannot activate a disabled window. This is the usual cause of popup windows re-activating the wrong window.

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.

MFC DoModal Dialog

Okay, so I will admit I have no knowledge of windows API or even MFC.
I've got an error window popping up when things go hairy (illegal character in a filename string) and I want the error box to be modal.
For the life of me I can't figure out why it crashes when it hits doModal.
Here is the code where I think this can be fixed. This code is in the event handler of a button in the main window.
CDialog *BadFileD = new CDialog();
BadFileD->Create(IDD_STATUS, this);
BadFileD->DoModal();
Am I just being borderline retarded?
MFC dialog divides two pattern, modal dialog and modeless dialog.
(1) Modal dialog usage:
CDialog dlg;
dlg.DoModal();
(2) Modeless dialog usage:
CMyDialog *pDlg = new CMyDialog();
pDlg->Create(ID_DLG, this);
pDlg->ShowWindows(SW_SHOW);
As you can see, we need a new pointer, but do not delete it. So, you need to do the following in our CMyDialog class:
Add DestroyWindow() method in OnOk() and OnCancel().
Add "delete this;" in PostNcDestroy() method.
If you do not, your code may cause a memory leak. BadFileD is a class member, and you delete it in destructor. I suggest use Modeless dialog.
For display modal dialog you should use DoModal method only
CDialog *BadFileD = new CDialog(IDD_STATUS, this);
BadFileD->DoModal();
You can read remarks from article
If you desire to just display an error message, it may be that rather than creating your own dialog you can just use AfxMessageBox(). See Microsoft Developer Network - AfxMessageBox.
If you want to do your own dialog box typically with an MFC project you would normally:
create a dialog box template using the resource editor
create a class encapsulating the dialog box with the class wizard implementing the behavior desired
insert the code to create and display the dialog box into the appropriate place
However with a simple dialog box that requires no supporting class for complex behavior you can skip the step of creating the encapsulating class with the class wizard and just use CDialog directly.
One question that needs to be answered is the lifetime of the dialog as well as whether it is to be modal or modeless. A modal dialog box requires the user to do something for the application to continue past the modal dialog box. A modeless dialog box does not block the application the way a modal dialog box does. There is also a system modal dialog box style.
Since you say it will be a modal dialog then the lifetime will be short so the entire construction, display, and destruction will probably be in a series of lines of code. For instance in a CView class with a command handler displaying a modal dialog box you might have:
void CViewThing::OnCommandMenuItem ()
{
CDialog BadFileD(IDD_STATUS);
int iRetStatus = BadFileD.DoModal();
// check for status such as IDOK, etc.
// do whatever is necessary.
}
What the above does is create a dialog box using the dialog resource template IDD_STATUS and displays it as a modal dialog box. Since it is local object, when the variable BadFileD goes out of scope, the dialog box destructor will be triggered and resources cleaned up for you.
You can also have a modeless dialog box. In the case of a modeless dialog box you need to consider the variable lifetime because as soon as the variable goes out of scope, the destructor will trigger and the dialog box will disappear.
So for a modeless dialog box being used with some view class, perhaps providing a tool box of some kind, the CDialog variable will be a member of the CView class which is using it. After the modeless dialog box is created, it is displayed or not by using the ShowWindow() member function of the CDialog class (actually a member of the CWnd class from which CDialog is derived).
void CViewThing::OnCommandMenuItem ()
{
BadFileD.Create(IDD_STATUS, this);
BadFileD.ShowWindow(SW_SHOW); // display the dialog
}
and in the CViewThing class you would have a member variable CDialog BadFileD;.
Additional considerations
In all of the above examples we are not using pointers so that when the CDialog variable goes out of scope, either from exiting a member function or when the object using the dialog box is destroyed then the dialog box is as well. This object management is done for us.
One thing that you must take into consideration with a modeless dialog box is how to destroy it when you no longer need it.
Since a modal dialog box is usually a short term object, often created as a local variable on the stack, you normally just let it go out of scope to take care of everything dealing with destruction.
However the lifetime of a modeless dialog box requires that the DestroyWindow() method be used to destroy the dialog box when it is no longer needed. See Microsoft Developer Network - Destroying the Dialog Box.
A third usage scenario - embedding a dialog box
There is a third usage of a dialog box that sometimes comes in handy, embedding the dialog box into another window as a control.
In the above examples, the dialog box template specifies the WS_POPUP style for the dialog which is the standard style for a dialog box since the normal way that a dialog box is used is to display as a separate window.
However if you change the WS_POPUP style to WS_CHILD you can then embed the dialog box into another window as a control. You can remove the other style settings such as WS_SYSMENU, DS_MODALFRAME, and WS_CAPTION and remove the CAPTION line from the dialog template to further change the dialog box. So you will end up with something like:
IDD_STATUS DIALOGEX 0, 0, 435, 266
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "this is some static text to display on this dialog.",IDC_STATIC,81,63,200,32
END
Then just use the resulting dialog box similar to how you would a modeless dialog box with ShowWindow().
If you need to reposition the embedded dialog box within its container window, you can use the SetWindowPos() method to do so. For instance the following would move the dialog box window within its containing window to be 20 pixels from the left and 10 pixels from the top of the containing window.
BadFileD.SetWindowPos(NULL, 20, 10, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER)

Convert a modeless dialog to modal at runtime

I have a dialog (CDialog derived class) that can be used in two different ways (edition mode and programming mode).
When the dialog is open to be used in programming mode it is a modeless dialog that it is used for modifying the main view (kind of a toolbar). When it is open in edition mode the user can change the configuration of the dialog itself and in this case it is a modal dialog.
Right now they are two different dialogs with few differences and I would like to have just want dialog and let the user change between programming mode and edition mode just by pressing a button in the dialog.
So I need to convert the modeless dialog in a modal dialog and vice versa at runtime. Is there a way to achive that?
Thanks.
As maybe someone could be interested in doing something similar in the future, this is the way I eventually did it:
I use this two functions of main frame: CMainFrame::BeginModalState() and CMainFrame::EndModalState().
The problem with these functions is the same that with disabling the parent window. The window you want to make modal also gets disabled. But the solution is easy, just re-enable the window after calling BeginModalState.
void CMyDialog::MakeModal()
{
//disable all main window descendants
AfxGetMainWnd()->BeginModalState();
//re-enable this window
EnableWindow(TRUE);
}
void CMyDialog::MakeModeless()
{
//enable all main window descendants
AfxGetMainWnd()->EndModalState();
}
Thanks for your help.
That can't be done easily without closing and reopening the dialog. Then you can call ShowWindow or DoModal as appropriate.
That is not correct. This can be done, if you look at MFC's source you will realize that it's modal dialogs are not technically even modal. You will have to do a lot of mucking about to make this work properly, but basically you just have to disable the parent of the 'modal' window, and re-enable it when the 'modal' window closes.
I have done this personally so this may work for you, though I am not exactly sure what you are trying to do.

How to hide a modal dialogbox in MFC application?

I have a hard time hiding a modal dialog box. What I am doing is - I am trying to design a UI for my own application in MFC, kind of a setup assistant.
In the 1st dialog box I have NEXT button, so when I click that it has to hide the 1st dialog box and move on to the 2nd dialog box, where I have some controls in 2nd dialog box.
How can I achieve that?
I have never tried to hide a Modal dialog...not sure how it can be done.
Anyway, it seems to me you don't need to hide the dialog but destroy the first one and create the second one. You can use EndDialog to terminate a modal dialog.
But MFC has its own mechanism to create your own wizard, have a look at this class CPropertySheet. I am sure you can find thousand of examples, this is one.
Hope it helps.
You can use ShowWindow() function to hide modal
Its default patametet is SW_SHOW which is equal true value 1 and
To hide modal use SW_HIDE value when you click next button
You just use ShowWindow(SW_HIDE) If you make prev button you should use modal pointer
Or next modal should child modal because you cannot have prev modal variable.
I wish you understand me for my english