?
Solved

Modal window with CreateWindowEx

Posted on 2003-03-06
12
Medium Priority
?
1,603 Views
Last Modified: 2013-12-03
Hi,

I am working on Win-NT and Win-2K with MS Visual C++ 6, using SDK (i.e. not MFC).

I have a custom window that I create with CreateWindowEx. I want to make this window modal (i.e. not only visible on top, but really modal, with the program waiting for the window to return).

Is there a mean to achieve this ? If you have a solution, please include an example of code.

Thanks for your help.
0
Comment
Question by:FLorenz
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
12 Comments
 
LVL 2

Accepted Solution

by:
northernchill earned 400 total points
ID: 8081908
You need to put a message loop in place.  This should be an infinite loop (it will be broken).  In this loop you process window Messages and pass along only those that apply to your window.  When the appropriate message is received break the loop, close the window and your done.

MSG msg;
ShowWindow(m_hWnd,SW_SHOW);
for(;;)
{
    if(PeekMessage(&msg, NULL, 0, 0,PM_NOREMOVE)){
        if(msg.hwnd == m_hWnd)
        {
             GetMessage(&msg, NULL, 0, 0);
             if(msg.message == UWM_EXIT)
                break;
             TranslateMessage(&msg);
             DispatchMessage(&msg);
        }
    }
}
ShowWindow(m_hWnd,SW_HIDE);
DestroyWindow(m_hWnd);

Replacing UWM_EXIT with an appropriate value for your program.  
0
 
LVL 2

Expert Comment

by:northernchill
ID: 8081916
Excuse me, the GetMessage call has to come before the if(msg.hwnd == m_hWnd)
0
 

Author Comment

by:FLorenz
ID: 8084196
Thanks northernchill,

While waiting for an answer from experts-exchange, I kept looking for some idea. I came to a very similar solution, inspired from
http://www.winprog.org/tutorial/message_loop.html
and from the Microsoft documentation.

Now, my custom window is created once, then shown and hidden several times: shown when needed by the main program, hidden when the user hits the "ok" or "cancel" button.

So I associated the following code with the "show" instruction

ShowWindow(m_hWnd,SW_SHOW);
while ( GetMessage ( &msg, NULL, 0, 0 ) > 0 )
  {
  TranslateMessage (&msg);
  DispatchMessage (&msg);
  }

and the following code with the "hide" instruction

ShowWindow(m_hWnd,SW_HIDE);
PostQuitMessage(0);

Looks simple isn't it? This seems to work perfectly.
Note the "while(GetMessage > 0)" instead of "while(GetMessage)", as suggested in the above-given reference. I also found a similar advice in Microsoft documentation.

Now, do you have any comment about this simplified version?
More specifically, what may I be missing by not calling the "PeekMessage" function nor doing the "if(msg.hwnd == m_hWnd)" test?

Thanks for your help. I'll give you the points anyway.
0
Free Backup Tool for VMware and Hyper-V

Restore full virtual machine or individual guest files from 19 common file systems directly from the backup file. Schedule VM backups with PowerShell scripts. Set desired time, lean back and let the script to notify you via email upon completion.  

 
LVL 2

Expert Comment

by:northernchill
ID: 8086444
The only thing that may occur is without the msg.hwnd == m_hWnd is that you will pass messages along to other windows in the application.  This may eliminate the Modality of your dialog.  The code I supplied was basic, you should also check the hwnd against child window handles if they are going to receive messages.

PeekMessage just looks at the message buffer to see if a message is waiting.  So you won't really loose too much by not calling this function. If you wanted to have some other processing while messages are not being relayed, then including the PeekMessage allows the program to continue through the loop if no message is available.  
0
 

Author Comment

by:FLorenz
ID: 8087750
Thanks for your comments and help.

To cope with child window handles, I tried replacing
  if ( msg.hwnd == m_hWnd )
by
  if ( IsCurWinOrSon ( msg.hwnd, m_hWnd ) )
with IsCurWinOrSon defined as

bool IsCurWinOrSon (
  HWND  hWndToCheck,
  HWND  hWndParent
  )

// Checks if hWndToCheck is hWndParent or (recursively) one of its sons.

  {
  if (hWndToCheck == (HWND)NULL)
    return false;
  else if (hWndToCheck == hWndParent)
    return true;
  else
    return IsCurWinOrSon ( GetParent(hWndToCheck), hWndParent);
  }

My window simply contains a combo-box plus "ok" and "cancel" buttons. Now, moving the window works, as well as hitting the buttons, but it freezes as soon as I touch the combo-box and I have to use the task manager to stop the application!!!

What is wrong?
0
 
LVL 2

Expert Comment

by:northernchill
ID: 8087813
Where does it freeze?  Can you break into the program when it freezes using the debugger?  There is probably a loop somewhere that is not receiving an exit signal.
0
 
LVL 2

Expert Comment

by:northernchill
ID: 8087964
Above TranslateMessage(&msg); add

if(PreTranslateMessage(&msg) == 0)
    TranslateMessage(&msg);

This allows proper handling for messages routed to child windows.

Sorry, it should have been in my original post.
0
 

Author Comment

by:FLorenz
ID: 8088346
Not yet solved, I am afraid.

Compiler says
error C2065: 'PreTranslateMessage' : undeclared identifier

From what I can find in the Microsoft documentation, this is an MFC function. Now, I am using SDK, not MFC...


I am still trying to find where it freezes exactly, but not yet found (I must say that I am not the original writer of this part of the program - always a big challenge).

What I can see is the following:
- when I click the combo box, it pulls down its options before the window completely freezes.
- just commenting out the "msg.hwnd" check is sufficient to make everything work fine (except that the window is not modal).

Seems to indicate that there is a message that is not dispatched while it should be. This is what I am trying to track. Now, it is so difficult to debug the message loop: messages keep flowing in all the time...
0
 
LVL 2

Expert Comment

by:northernchill
ID: 8088590
Yes you are right.  My apologies, I am shifting out of MFC mode with this and sometimes still fall back into old train of thought.

Try dropping down the list, typing in the edit box of the combo box and then press enter. This should close the drop down and free the mouse to interact with the dialog again. I think what happens, is your drop list sets itself up to track the mouse, but the mouse messages don't make it there.  However, pressing Enter in the edit should tell the combo box to release its mouse tracking all should be well.

What does this mean for your program?  I am not sure.  I will have to think about it a little.  The answer is not coming into my mind right now.

0
 
LVL 2

Expert Comment

by:northernchill
ID: 8088913
Allright, here the answer that should have been posted to begin with:

Use a dialog template (still acceptable in your SDK project?).

Call
::DialogBox(m_hInstance,MAKEINTRESOURCE(YOUR_TEMPLATE_ID),NULL,YourDialogProc);

This will create a Modal Dialog Box for you (and handle the message dispatching).

YourDialogProc looks something like:
BOOL CALLBACK StdDialogProc(HWND hwndDlg, UINT uMsg, PARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
// Handle messages here
   case WM_INITDIALOG:
      // Initialize your dialog box
   case WM_WHATEVER
      // Perform whatever processing you need done depending on the message
   case WM_COMMAND:
      switch (LOWORD(wParam)) {
      case IDOK:
         EndDialog(hwndDlg,0);
      case IDCANCEL:
         EndDialog(hwndDlg,
      }
    default:
      return FALSE; // Message wasn't handled
   }
return TRUE; // Message was handled

}

If you can use a template then this is the way to go.
0
 

Author Comment

by:FLorenz
ID: 8089175
Regarding keyboard input:
Indeed, the keyboard works: I can move in the list for instance with the keyboard "up" and "down" arrows, then select an item by pressing the "enter" key. It closes the drop down and the mouse can be used again, as you predicted.
Well done! Looks like you have some experience...
I think I'll have to dig out the portion of code managing that combo box and try to understand how it works exactly.
Not easy because the whole thing has been based on (a modified version of) MIRO to make it compatible to both Windows and OSF/Motif. So there are layers over layers over layers...

Regarding the dialog template:
Why not a dialog template? This has been my first question too. Not so easy to change due to the layered architecture I mentionned. I asked the guy who originally did this part of the program but he does not remember exactly.
Note that this window was originaly not modal and it was ok. The problem is that it needs to be modal now, so I try just to change this aspect and nothing else. Should be the fastest way, although I begin to doubt.

Thanks for your appreciated help.
0
 

Author Comment

by:FLorenz
ID: 8105553
At last it works. Yeah!

The problem is with the combo-box. When one clicks on the selection field, a message is sent to the combo-box that drops down the list-box. Then the list-box captures the mouse, waiting for a selection. The problem is that the list-box handle is apparently not a (grand)child of the combo-box (a bug of Windows?) so that my message loop will not execute further mouse messages.

Now, finding a solution gave me some headhache. As the combo-box is a predefined Windows control, there is no means to change the characteristics of its embedded list-box.

I eventually found a quite tricky means. I simply changed my message filter in

  if ( IsCurWinOrSon ( msg.hwnd, hwnd ) || msg.hwnd == GetCapture() )

The messages are still executed if they adress the handle that captured the mouse i.e. the list-box. This works.

Does anyone see any sort of problem with this method? (or is there a less tricky method?)
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
This article surveys and compares options for encoding and decoding base64 data.  It includes source code in C++ as well as examples of how to use standard Windows API functions for these tasks. We'll look at the algorithms — how encoding and decodi…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…

770 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