Link to home
Start Free TrialLog in
Avatar of Ballad
Ballad

asked on

How do I detect a modal dialog box?

I want to detect a modal dialog box, with a given hwnd. The modal dialog box is not created by my thread.
Avatar of AlexFM
AlexFM

From MSDN topic DialogBoxParam:

The DialogBoxParam function uses the CreateWindowEx function to create the dialog box. DialogBoxParam then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT or DS_SHELLFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), 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, DialogBoxParam 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.

This can give a direction. Call IsWindowEnabled for parent window. This is not a universal solution, but may work in your case.
Avatar of Ballad

ASKER

I don't want to create a dialog box. I want to be able to decide that it is a dialog box.
Avatar of jkr
Identify the window class name. If it is '#32770', it is a dialog (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowclasses/aboutwindow.asp), e.g.

HWND hWnd = ...;
char acClassName [ 255];

GetClassName ( hWnd, acClassName, sizeof ( acClassName));

if ( !lstrcmp ( acClassName, "#32770")) {

// window is a dialog

} else {

// window is NOT a dialog

}


Avatar of Ballad

ASKER

thanks, but there are class names != #32770 which are still dialogs, so the question remains...
Try:

GetWindowLong(hWnd, DWL_DLGPROC)

If that fails (returns 0), and GetLastError() returns ERROR_INVALID_INDEX, it's not a dialog box.

I don't know of any way to distinguish between modal and modeless dialog boxes, though.
I mean, check if window's parent is disabled. If yes, this is modal dialog. Additional criteria is class name, as jkr writes.
Applying these two conditions can give a good result (I don't think 100% right, but may be acceptable).
Here is an important consideration:
In MFC, and OWL, and presumably many how-grown foundation classes, ALL MODAL dialog boxes are actuallu MODELESS dialog boxes.

The underlying support simulates the "internal message pump" that "true" modal dialogs use.

SO!  Even if you were to ascertain that a particular dialog is a modeless dialog, odds are that it is really a acting as modal dialog and you'd have what's called a "false negative" on your modal test!

Now, take a few minutes and describe your question in more detail.  Explain WHY you want to detect a modal dialog box and what you intend to do when you find one.  It's not me being idly curious... it's me trying to solve your ACTUAL problem and not some (possibly unrelated) sub-problem.

-- Dan
Avatar of Ballad

ASKER

reply to DanRollins:

I have two applications that my application supervise. My application is meant to be a single sign on app. That is, if you logon on one app my singlesignon app will logon the other app as well. The problem is in logging off. If you logoff one app and the other has a dialog box, I want to kill that dialog window, or perhaps emulate a CANCEL push, to get rid of the window. But I must detect that it is a dialog box. Thats my problem.
If you send a WM_QUIT to an App's main window, it should shut itself down, even if a modal dialog is being displayed.

If you have control of the source on both apps, you can use RegisterWindowMessage to define a custom message, say WM_MyShutDownNotice.  Then when one app is shutting down, broadcast that message, or post it to the other app.  Then when you get that message, handle it by cleaning up and shutting down.

-- Dan
Avatar of Ballad

ASKER

I made a test on notepad. The about box is very much modal. It has no parent. So that fails that test (to AlexFM).

When I try GetWindowLong(hWnd, DWL_DLGPROC) and GetLastError(), in my little test app, on that about box I get 0 and ERROR_ACCESS_DENIED resp. Because that about box is not created by me but by notepad. (TascoDLX).

To Dan: Is the bottom line, what you are saying, that I can't decide wether it is a modal box or not?
Ballad,

GetWindowLong() gave you ERROR_ACCESS_DENIED because it *IS* a dialog box and it won't let you touch its DialogProc.

As for determining modal and modeless, there are quite a few factors that could fudge your test.

Bottom line:  With the IsWindowEnabled() method, you can ONLY assume a modal dialog box if GetParent() returns a valid hWnd *AND* IsWindowEnabled() return FALSE.

If someone has another method of determining modal or modeless, I'd sure love to see it.
Avatar of Ballad

ASKER

i must melt this, have a cold so my brain is not on top ..sorry
Avatar of Ballad

ASKER

TascoDLX: Why is this true?

"GetWindowLong() gave you ERROR_ACCESS_DENIED because it *IS* a dialog box and it won't let you touch its DialogProc."

I mean that I got ERROR_ACCESS_DENIED because we are two separate processes, my app and notepad. To receive an address to another dialog box procedure in another process is meaningless in win2000 or WinNT. We cannot communicate, unless we use hooks.



ASKER CERTIFIED SOLUTION
Avatar of TascoDLX
TascoDLX

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> what you are saying, that I can't decide wether it is a modal box or not?

I'm saying that in the situation that you described, you might not need to know.

Anyway, you could try either of these methods:

1) Enumerate the desktop windows using EnumWindows(), determine which is the correct window, obtain the thread ID with GetWindowThreadProcessId(), and post a WM_QUIT message via PostThreadMessage() to terminate the application.

2) Use the TOOLHELP APIs. Use Process32First() and Process32Next() to enumerate the tasks, determine which is the correct task, and call TerminateApp() to kill the application.

Note that the GetWindowThreadProcessId and GetWindowLong(...,GWL_HINSTANCE) APIs could come in handy.

-- Dan
Don't mean to be curt, but this will work for most standard dialog boxes:

   PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(nID, BN_CLICKED), 0);

Possible values for nID are IDOK, IDCLOSE, IDCANCEL, IDABORT, IDIGNORE, IDNO.

For a simple 'About' box, IDOK will work.

Obviously, every situation is going to be different.  IDCANCEL may work, IDCLOSE may work.  I'm sure there are situations where none of them will work.  You may have to post the WM_CLOSE message directly.  Or you may not have a clue.

I don't know what kind of apps you're working with, but if you're dealing with any application (user's choice), you'll probably run into situations where you can't close a dialog.  Sometimes, you just don't know.
Avatar of Ballad

ASKER

to DanRollins: I don't want to kill the app. I want to make a graceful logout. The app has a logout button in a toolbar. But the problem is, once again, that I can not emulate a mouse click on that logout button if I have a modal window, waiting for input. So if I know that the window is modal, I can simply send a WM_CLOSE to that window, it closes, and I can emulate a nice logout. When that is done, the apps, login window appears and I can start the login process on the two apps again. Referring to previous comment, describing my single sign on app.

Thanks anyhow that you all take part in my problem. It is very important that I solve it.
Avatar of Ballad

ASKER

Thanks TascoDLX, very ingenious.