MFC: Prevent CDialog from being hidden when main window is minimized? - winapi

I have a derived CDialog (actually CBCGPDialog) that was created with a NULL parent window. Yet, when I minimize the main program the dialog goes away. If I do something like:
void CMyDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
CBCGPDialog::OnShowWindow(bShow, nStatus);
if (bShow==0 && nStatus==SW_PARENTCLOSING) {
ShowWindow(SW_SHOWNORMAL);
}
}
It will open it back up but there is a flash. Where would I catch the minimize request in CMyDlg to prevent it from minimizing? (This dialog only has a close option on it, so if they don't want it shown, they would close it, it contains more of a window to show stuff than a normal dialog of options, maybe I should move it to a CWnd?)

Related

How to capture the action about starting dragging a window and releasing the capture of a window?

When cursor honver over the title zone (HTCAPTION),press left mouse button, then you can drag a window and move it. When you release the left mouse button , you can stop this dragging action. When you move a window , it triggered the message WM_MOVE. When release the mouse button , I don't know which message should be handled for catching this action.
What I'm doing is when you drag a window(let's say window A) into another window's area(window B), make window A a child window of window B, when drag window A out of window B's area , make window A a WS_POPUP window, without WS_CHILD style.
I handled message WM_MOVE and WM_CAPTURECHANGED( I don't think it's the right one).
In WM_CAPTURECHANGED , I found something wired. The API SetWindowPos seemed not work well. To be percise, the 3rd and the 4th parmater , specified the window's position not work.
case WM_CAPTURECHANGED: {
RECT rcc;
GetClientRect(main,&rcc);
// here main is the handler of window B , hwnd is for window A,as referrence above.
if(docker_mode==DOCKER_LEFT) {
// docker_mode is assigned by WM_MOVE message handler. recording which area window A was moved into.
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))!=WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,(~WS_POPUP)&(WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE)));
SetParent(hwnd,main);
}
//The following code not work. It should be moved into the left-top corner of window B,
//but NOT in fact.
SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_NOZORDER);
}
else {
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,((~WS_CHILD)&GetWindowLongPtr(hwnd,GWL_STYLE))|WS_POPUP);
SetParent(hwnd,NULL);
SetWindowPos(hwnd,NULL,300,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
}
}
} break;
SetWindowLongPtr(...,GWL_STYLE,...) was called to set the window style . A top level has no WS_CHILD style, and the handle of parent window should be NULL , I use SetParent(hwnd,NULL) to do this. A child window should have WS_CHILD style, and the parent window should be assigned.
I put a button into the window , and copy those code into the handle of button click event. When click the button it works well , change a popup window into a sub window , put the sub window into right position. SetWindowPos has no problem at all. I don't know why.
SetWindowPos is a very interesting API when working on WM_CAPTURECHANGED handler. What's wrong ?
If I recall correctly, when the user drags a window, that window receives a sequence of messages like this:
WM_ENTERSIZEMOVE
WM_WINDOWPOSCHANGING
WM_MOVING
WM_WINDOWPOSCHANGED
WM_MOVE
WM_EXITSIZEMOVE
(There are other messages, too, but I don't think you need to worry about those. There may be some final messages after WM_EXITSIZEMOVE with the final resting place for the window.)
The steps in the middle will happen repeatedly as the user drags the window. (In the Old Days, only some of those middle steps would happen, and there may still be an option to cut down on the messages during the drag operation.)
You can try using Spy++ (included with Visual Studio) to confirm the above.
So you shouldn't need to deal with the mouse capture messages. Have window A watch for WM_EXITSIZEMOVE. At that point, window A can check its position to see if it overlaps the target window (B). If it does overlap, then it should send a message to window B to initiate the docking operation.

MFC: how to show a welcome dialog first?

When launch the program, I want to show a welcome dialog first before showing the main window. My current approach is like below.
BOOL CMyApp::InitInstance()
{
...
// The one and only window has been initialized, so show and update it
m_pMainWnd->ShowWindow(SW_HIDE);
//m_pMainWnd->UpdateWindow();
// call DragAcceptFiles only if there's a suffix
// In an SDI app, this should occur after ProcessShellCommand
CWelcomeDialog welcome_dialog;
welcome_dialog.DoModal();
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
Towards the end of InitInstance(), originally it uses (SW_SHOW). At first, I try commenting it out but it still shows. So I change to (SW_HIDE). It works but has unpleasant visual artifacts. Is there way to stop showing the main window as early as possible?
Another issue is that when I hide main window and show the dialog, the dialog is not in the center position of the main window.
In general, how to implement a welcome dialog and to show it well-centered before anything else?

How can a dialog become responsive while waiting for a call to DoModal() to return?

A button on a dialog causes a child dialog to be created, and displayed modally.
e.g:
void ParentDialog::OnButton()
{
ChildDialog dlg;
int ret = dlg.DoModal();
}
The parent dialog is initially unresponsive as expected. But, the child dialog also makes COM calls to a server module, which causes the server to make COM calls back to the parent dialog... to update displayed data, etc. In one case, this causes the parent dialog to suddenly become responsive again even though the child dialog is still on screen. Both dialogs can now be interacted with even though the parent dialog is still patiently waiting for OnButton()to return.
How can this happen? I'm trawling the code but is there anything specific I should be looking for?
The dialog has its own message pump/loop and inside the call it has a loop where it keeps receiving and dispatching window messages. This includes COM related messages worker windows receive and convert to COM callbacks you are seeing. Once the dialog is closed, respective windows are destroyed, the function exits from the loop and returns control to your code.
That is, without returning control to your code immediately, window message dispatching still keeps working as usually and UI is responsive.
MSDN:
... The function displays the dialog box, disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.
When the dialog box procedure calls the EndDialog function, DialogBox destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter specified by the dialog box procedure when it called EndDialog.
You can create a modeless dialog and use RunModalLoop to wait for the dialog to finish, somewhat similar to DoModal()
void CMyWnd::foo()
{
static BOOL isOpen = FALSE;
if (isOpen) return;//optional, prevents opening multiple dialogs
CDialog dlg;
dlg.Create(IDD_DIALOG1, this);
dlg.ShowWindow(SW_SHOW);
isOpen = TRUE;
int result = dlg.RunModalLoop(0);
dlg.DestroyWindow();
isOpen = 0;
TRACE("res:%d\n", result);
}
Problem: Note that in the above example you can close the program but the dialog will still be up. You have to force the dialog close, the above function doesn't deal with that.
Or you can create modeless dialog the usual way:
if (m_Dlg) return;
m_Dlg = new CDialog
m_Dlg.Create(IDD_DIALOG1, this);
m_Dlg.ShowWindow(SW_SHOW);
However in this example if user clicks OK/Cancel then you don't know about it, you have to override OnOK()/OnCancel then send message to parent Window/Dialog, process message, and then destroy the dialog manually.

How to show a dialog from another dialog?

I am newbie to MFC. I have a native C++ MFC app. I want to show a dialog from main dialog. In the main dialog I am having three button (Back, Next, Cancel) respectively.
On the Next button click event I am calling DoModal to show another dialog by hiding the main dialog as follows,
void CFirstPage::OnBnNextButton()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CSecondPage secondDlg;
secondDlg.DoModal();
}
void CSecondPage::OnBnBackBtnClicked()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CFirstPage FirstPage;
FirstPage.DoModal();
}
After executing this code snippet, the main dialog got hidden and even the application icon also disappears from the taskbar and again appears when the other dialog pops up.
(Basically I am having the same icon for both the dialogs, the icon should not get disappeared and appear again. It has to remain same without appearing and disappearing .)
How can show the icon in the taskbar without any flickering effect?
During traversing from back to next in middle I clicked cancel and the Cancel event is handled as follows,
void CFirstPage::OnCancel()
{
CDialog::EndDialog(TRUE);//For closing the dialog.
}
void CSecondPage::OnCancel()
{
CDialog::EndDialog(TRUE);//For closing the dialog.
}
Steps1:Click Next in the main dialog
Step2: Click Cancel in the second page
Now the application closes. But still instance is active in the "TaskManager". As per my understanding no instance should be alive once windows is closed ?
I suspect as the first dialog is only hidden not ended that instance is still existing in the TaskManager. Is this understanding correct?
How can I resolve this issue?
Can anyone kindly help me to resolve this issue.
As said by Iinspectable property sheets are best suited for your your problem statement.A very good example on how to use CPropertysheets can be found in codeproject
CProperty sheet example
Probably your main windows is still hidden after you end dialog with second page. Ending dialog of CSecondPage does not close application only closes active CSecondPage dialog.
Also OnCancel/OnOK does not need to be overriden if you just EndDialog with it. There is default behaviour implemented in OnCancel, which will close the dialog.
After secondPage.DoModal() show your main dialog again, or close it if that is the behaviour you want to achieve.
FirstPage isn't the original first dialog now, so you should store the first dialog object by yourself. You can do that like this:
void CFirstPage::OnBnNextButton()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CSecondPage secondDlg;
secondDlg.setFirstDialog(this); //customer function to store first dialig object
secondDlg.DoModal();
}
void CSecondPage::OnBnBackBtnClicked()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
::ShowWindow(m_firstDialog->GetSafeHwnd(), SW_SHOW);
}

Win32 App (Aero): Prevent dialog move

I've a dialog based Win32-app on Win7-Aero which only displays a dialog. The dialog should have a title bar. I don't want that the user can move the dialog on the screen.
I've no luck so far... handling WM_NCHITTEST, WM_SYSCOMMAND... setting SWP_NOMOVE.
What is the best way to achieve NoMove? I think DWM changes something on Win7.
You could do this by handling WM_WINDOWPOSCHANGING and when you see an attempted move, change the coordinates back to where they should be. E.g.
switch (uMsg)
{
case WM_WINDOWPOSCHANGING:
if (!(reinterpret_cast<LPWINDOWPOS>(lParam)->flags & SWP_NOMOVE))
{
reinterpret_cast<LPWINDOWPOS>(lParam)->x = g_iMyXCoord;
reinterpret_cast<LPWINDOWPOS>(lParam)->y = g_iMyYCoord;
}
return 0;
}
You would probably need to add some intelligence to this to distinguish between attempted moves by the user, and moves that your own program makes (or that the system makes if necessary - e.g. if a monitor disappears for instance).
Even though you say it doesn't work, I would have thought you could also do this by trapping WM_NCHITTEST and returning HTBORDER whenever HTCAPTION would have been returned - however you would have to do this by sub-classing the window rather than in the DialogProc (because you would need to call the default handler first and then process/change the return value). Same for WM_SYSCOMMAND (to catch moves the user attempts via the system menu).

Resources