Solved

Why is Popup Window Displaying Behind other Application Windows

Posted on 2008-10-30
11
934 Views
Last Modified: 2013-11-20
I have an MFC Dialog application with an outline of the code shown in the code snippet below.  Conceptually, I display a Login Dialog, when login is successful, I display a splash screen while the main Dialog window is initilized and data files are loaded into memory.  As laidout in the snippet below, the Login window will apper above any existing applications, the splash screen then displays BEHIND any existing application windows, and then the main Dialog displays above any existing applications.  
But now this is where is gets weird.  If I modifiy the code to skip the login screen, the splash screen displays INFRONT of existing application windows.  The splash screen also displays INFRONT of existing application windows if I create it on the stack inside of CMyDlg.OnInitDialog() .  It seems the only time the splash screen displays behind existing windows is in the desired senario (as outlined below).
Now I know one fix is to just create the splash window with WS_EX_TOPMOST.  But that seems like a silly bandaid.  I'm trying to find out from an education standpoint WHY the splash screen appears behind existing windows.

For what it's worth, in the snippet shown below, CSplashScreen is a wrapper class around the logic for the REAL splash screen code.  The REAL splash screen code runs in a seperate UI Thread.  The Splash Screen consists of a CWnd derived POPUP window with child windows created with MCIWndCreate.  The Splash Screen actually displays an AVI file in a seperate thread while the data is loaded in the main thread.

Obviously lots of code has been left out (like exactly how the 2nd thread is started and all the other stuff needed to make this stuff work.

But the crux of the issue is the fact that my splash screen shows as the top window IF I either skip the login screen OR move the instance of the CSplashScreen object to the local stack in OnInitDialog() rather than as a member object of CMyApp.

BOOL CMyApp::InitInstance()

{

  //General init code here

  //  Such as INITCOMMONCONTROLSEX and CWinApp::InitInstance()
 

  m_SplashScreen.Initilize(); //Does things like creates the windows 

                              //but keeps the main window hidden

  INT_PTR nResponse = IDRETRY;

  while( nResponse == IDRETRY )

  {

    CLoginDlg dlg;

    dlg.DoModal();

    if( dlg.IsGood() ) nResponse = IDOK;

  }

  if( nResponse == IDOK )

  {

    m_SplashScreen.MakeVisible();  //Appears BEHIND other applications

    CMyDlg dlg;

    m_pMainWnd = &dlg;

    dlg.DoModal();

  }

  return FALSE;

}
 

BOOL CMyDlg::OnInitDialog()

{

  //General Init code here, like CDialog::OnInitDialog()
 

  //Optional Location for SplashScreen...

  //CSplashScreen Splash; Splash.Initialize(); Splash.MakeVisible();
 

  //Dialog Initilization code here

  //  Includes creating child windows and loading data files
 

  //SplashScreen.Finished();

  g_App.HideSplashScreen();  //CMyApp Function that calls CMyApp::m_SplashScreen.Finished()
 

  return FALSE;

}

//If code referencing CMyApp::m_SplashScreen is commented out

// and uncomment out the Splash Screen created on the stack here

// the Splash Screen displays as normal.

//But as shown, or even if I mode the logic that makes the 

// CMyApp::m_SplashScreen become visible from within CMyDlg::OnInitDialog()

// The splash screen appears behind other application windows.
 
 

//Crude Outline of class that builds the actual splash screen

CSplashWnd::Create()

{

  //Create 'this' Main Window

  CWnd* pDesktop = GetDesktopWindow();

  CRect ScreenRect; pDesktop->GetWindowRect( ScreenRect );  

  int Width = ScreenRect.Width(); int Height = ScreenRect.Height();

  CreateEx( WS_EX_STATICEDGE, AfxRegisterWndClass( 0 ), "Splash Screen", WS_POPUP, 0, 0, Width, Height, NULL, NULL ) );

  //Create AVI window

  DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_DISABLED | MCIWNDF_NOMENU | MCIWNDF_NOOPEN | MCIWNDF_NOPLAYBAR | MCIWNDF_NOERRORDLG | MCIWNDF_NOTIFYMODE;

  m_hAVIWnd = MCIWndCreate( m_hWnd, AfxGetInstanceHandle(), dwStyle, m_FileNameAVI );

}

Open in new window

0
Comment
Question by:HooKooDooKu
  • 6
  • 4
11 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 22848643
The most common reason for unexpected window layering relates to the parent/child relationship.  In your example, you set the parent to 0, which will make it your main window. The spladh screen is also created without specifying its parent (it is a seldom used parameter of the constructor -- see http://msdn.microsoft.com/en-us/library/8zkyyhxw(VS.80).aspx )
When you get the parent/child relationships straightened out it will work as expected -- child windows in front of parent, erc.
0
 
LVL 16

Author Comment

by:HooKooDooKu
ID: 22849710
The idea of parent/child relationship is interesting, but in this case, the windows don't have a parent/child relationship.  In this case, the application simply has three windows that display in series... Login, then Splash, then main Dialog.  Plus the splash screen isn't a CDialog, it's a WS_POPUP window, so the article referencing the Parent parameter for a CDialog object seems irrelevant to this situation.

Basically, the Login and MyDlg ARE CDialogs, and they are behaving as desired.  It's just this CWnd derived, WS_POPUP, SplashScreen that displays between the two CDialogs that is misbehaving depending upon the situation.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 22853256
>> the windows don't have a parent/child relationship.
That's waht I said.  That is the problem.  They should; they need to have such a relationship to ensure that you can control which is on top of the other.
0
 
LVL 16

Author Comment

by:HooKooDooKu
ID: 22864640
>>That's waht I said.  That is the problem.  They should; they need to have such a relationship to ensure that you can control which is on top of the other.

Those words sound like you mean that the windows need proper parent/child relationships within my project so that I can control which window is on top of which window within my application.  But the problem isn't within the application (where I would suspect dynamic modification of Z order would take care of which is in front and which is in back).  

But within my application, these windows logically do not have a parent/child relationship.  Logically speaking, they are a series of modal dialogs.  The two that are true dialogs are not causing a problem.  The one that is causing a problem isn't a modal dialog, it's a CWnd POPUP with child MCI A/V windows.  The only other odd thing is that this POPUP runs in a 2nd thread while the primary thread loads data.

I guess the only thing I can think of to force the parent/child relationship suggested would be to make a primary parent window... but this would be a parent window in name only.  I'd never want to have anything with this window shown, it just needs to be a virtual window that can be a parent window to dialog windows and a POPUP window.  But is that sort of thing even possible?
0
 
LVL 1

Accepted Solution

by:
houyaopan earned 500 total points
ID: 22871726
If that popup window is not modal, you can BringWindowToTop() right after you call ShowWindow() (or when you call SetWindowPos() to show the window).
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 49

Expert Comment

by:DanRollins
ID: 22872143
I haven't ever tested this kind of scenario -- a fullscreen pop-behind "splash" window is, to say the least strange.  One that is running on a separate U/I thread showing an AVI file is beyond that -- somewhere in between X-files and Fringe.  Doing anything full screen (with the exception, perhaps, of a program installer) is almost always inadvisable.  People want to see the windows that they have opened and been using and they want to see the desktop everywhere elese.
You might be able to make the whole thing hang together by being specific about the parent of each window -- if you use NULL, MFC might  need to decide which window is the main one and the fact that you have two U/I threaded windows probably casues some confusion.
So, set the parent of the splash window to the value returned from GetDesktopWindow().  Anything that you want to have above that in the Z-Order should have the splash window as its parent, until such time as the splash window closes (when you should probably re-parent to the desktop).
As to the behavior of windows in other currently-running application programs:  You don't really control them.  The O/S sees that you are the newest app and it will naturally want to put your window in front of the other apps.  I actually don't understand how you get the "pop behind" functionality in any scenario.  I think it must be some kind of quirk.  But it might be related to the style bits used.  All I can suggest is that you try various combinations until you see the behavior that you want.
0
 
LVL 16

Author Comment

by:HooKooDooKu
ID: 22872508
Well, I've found an alternate solution.  I don't know why, but when I change the code to make the Parent window of the 2nd thread a simple invisible child window of the desktop, and then make the MCIWnd a WS_POPUP with the invisible child window as the parent, and then make the MCIWnd visible... it works.

So I still don't have a solution to the real question (why the initial implementation always popped up behind other windows unless I used TOPMOST), I'm going to award points for the "BringWindowToTop()", because I would have likely tried that as a means of getting the desired window to the top without making it Top Most Window.  Unfortunately, I've made too many code changes to go back and see if that would be a solution... but I feel like it was heading me in the right direction.
0
 
LVL 16

Author Closing Comment

by:HooKooDooKu
ID: 31512931
Only awarding a C because the "solution" didn't answer the question of "why" this was occuring.  But I'm accepting the answer as a solution as it sounded like a way that I could have brought the window to the top without resorting to TOPMOST.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 22873822
>> when I change the code to make the Parent window of the 2nd thread a simple invisible child window of the desktop, and then make the MCIWnd a WS_POPUP with the invisible child window as the parent, and then make the MCIWnd visible... it works.

So it worked when you set up a proper parent /child relationship.
What an incredible coincidence!
I wish I had thought of suggesting that!. Oh, wait.... I did.
0
 
LVL 16

Author Comment

by:HooKooDooKu
ID: 22876731
>>So it worked when you set up a proper parent /child relationship.

No, not really.  Perhaps I wasn't totally clear, so I'll try to explain one last time.

Application had three primary windows that displayed in series.  The desktop was and is the parent of each one of these three windows.  The problem is that the 2nd window in the series is running in a second thread and would always display BEHIND any other applications already running on the desktop.

Now, focusing on the second window... it was a WS_POPUP window with the desktop as it's parent.  This popup window then had a WS_CHILD window that played the video.

What worked was when I changed the WS_POPUP parent window to a WS_CHILD window and made it invisible, and made the video window a WS_POPUP, with the WS_CHILD window as it's parent.  The WS_CHILD window remained invisible, such that it was really nothing but a place for a message loop to run, and something to be a parent for the video window.

So it possibly seems that my error was in making a WS_POPUP a child of the desktop, and placing child windows within that popup (but I don't see why that would be a problem and no one said it would be a problem).  

So, from my point of view and limited understanding of MFC, I did NOT change parent/child relationships of any of the windows of the application.  I simply changed the STYLE of two of my windows from WS_POPUP / WS_CHILD to WS_CHILD / WS_POPUP.  I still don't understand why it works... but it does.
0
 
LVL 16

Author Comment

by:HooKooDooKu
ID: 22876808
Well crap, I was wrong.  It isn't working correctly.  It appears to be working ok now on XP, but when I run it on Vista, the second window STILL appears behind other applications.  Time to actually try BringWindowToTop()
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
while loop over for loop 7 79
tripleUp challenge 7 67
sumHeights  challenge 17 61
wordcount challenge 11 76
This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now