What is the DS_CONTROL style for?


The DS_CONTROL dialog box style indicates that the dialog being created is being used as the child of another dialog rather than being a top-level dialog in and of itself.

Nested dialogs are hardly a scary sight. You see them in property sheets, for example. Each page on a property sheet is a separate dialog; they all live inside the outer dialog, the property sheet itself. Nested dialogs are sometimes used in the common file dialogs: You can see one in action if you do a Save As from Notepad. The extra options at the bottom come from a nested dialog.

When you set the DS_CONTROL style on a dialog template (or set the WS_EX_CONTROLPARENT extended style on a regular window), a bunch of new rules kick in.

First of all, the WS_CAPTION and WS_SYSMENU styles in your dialog template are ignored. Because you're a child window now, not a top-level window, so you don't get a caption bar or a system menu. (The caption bar and system menu come from the outer window.)

Next, the dialog navigation functions like GetNextDlgTabItem will recurse into windows marked WS_EX_CONTROLPARENT when they inspect the controls on a dialog box (in GetNextDlgTabItem's case, because it is looking for a control to tab to). Without the extended style, the control search treats the embedded dialog box as one giant control rather than as a container for other controls.

When you create a dialog with the DS_CONTROL style, you invariably use one of the creation functions like CreateDialogParam rather than one of the dialog box functions like DialogBoxParam, because the modal loop is controlled by the outer dialog, not the inner one.

The recursive behavior is important to know in order to avoid sending the dialog manager into an infinite loop. When you ask GetNextDlgTabItem to look for the previous item, what it does is take the starting control, then walk through the controls on the dialog until it comes back to the starting point, at which point it returns the one it saw before that one. If you forget to mark your dialog as DS_CONTROL, and focus started out in the sub-dialog, then the control enumeration will not recurse into the sub-dialog and consequently the starting point will never be found. The dialog manager will just keep looping, hunting for that starting-point control and never finding it.

(This problem exists even without DS_CONTROL. If you start out on a disabled or invisible control, then the walk through the controls will again never find the starting point, since disabled and invisible controls are skipped over when tabbing through a dialog.)

Comments (16)
  1. Can you tell the .net team about this please?

    There is a bug in .net (all versions) where if you open a dialog parented to an mdi parent control and in that dialog open another dialog, and it fires the DialogResult.OK, it will close both dialogs instead of just the top level one, both with DialogResult.OK. Sure sounds like it’s a bug in the way they’ve implimented what you’re talking about here!

  2. Raymond Chen says:

    If you parent a dialog inside another, then OK for one = OK for all. Look at property sheets for an example.

  3. Brad C. says:

    Notepad is a rather poor implementation of the nested dialog. Everything looks fine with the default layout, but try disabling the places bar via Group Policy or TweakUI. The right edge of the Encoding: dropdown gets clipped by the right side of the dialog, and the corner gripper edges up over it 1 or 2 pixels. The dropdown appears to be left-justified to the larger "with places" dialog, so once the places bar is no longer present, the left margin is far too much.

    Ironically, the Group Policy description for the "Hide the common dialog places bar" specifically mentions the File, Open… dialog in Notepad, in which this erratic behavior can be observed.

  4. Raymond Chen says:

    Yup, this is a general problem with all apps that customize the common file dialogs – they don’t know what policies are in effect and therefore cannot adjust their customization accordingly.

    Wordpad is another example of a program that passes a customization subdialog.

  5. Seth McCarus says:

    I’ve run into the infinite looping problem with several apps… but only when DS_CONTROL and / or WS_EX_CONTROLPARENT are set. I had a top-level dialog with a child tab control, which in turn had child dialogs. The only way I could enable DS_CONTROL and avoid hanging was to make the dialogs children of the main dialog, not the tab control. I don’t know if that was the correct solution or not.

    Raymond, could you please explain the difference between DS_CONTROL and WS_EX_CONTROLPARENT? How they relate and when they should or should not be used together. Thanks!

  6. Ben Cooke says:

    Is there some special reason why the extra child dialogs in the common file dialogs aren’t shifted along to align with the existing controls in the dialog?

    I suppose it’s possible that an application could theoretically want to fill the entire width of the dialog down there, but given that there was a time when there was no places bar at all I would expect the designers to allow for this by "magically" adjusting the position for the new version of the dialog, so that the pre-places-bar apps don’t do odd things.

    The Notepad problem has amused me for some time. I don’t have Wordpad so I hadn’t noticed it in there.

    Is there a recommended solution other than just not turning off the places bar? I imagine the resizable common dialogs as of Win98 (or there abouts) must cause similar troubles.

    (The places bar is rendered essentially useless by the Windows "drive letters" scheme, which means that my data has to be rooted an several different places. To start off with I was fixing this with NTFS Directory Junctions but I got bored of maintaining them. I have no place to point "My Documents" at which encapsulates everything and that is why I disabled the useless toolbar.)

  7. Mike says:

    Ok – I understand

  8. Raymond Chen says:

    Ben: They aren’t shifted because that would break code that assumed that they aren’t shifted (which they never were before Windows 2000).

    Turning off the places bar was added at the request of corporate administrators; it wasn’t meant to be something average users did.

    Seth: Please hold off on further questions about dialog boxes; I have been developing a series on dialog boxes and your question is answered there.

  9. Seth McCarus says:

    Hmm, after messing around a bit more I found that if I use SetWindowLongPtr to add the WS_EX_CONTROLPARENT style to my tab control, I can leave the dialogs as children of the tab (not the top-level dialog). Works fine, and I guess that’s the "correct" way to do it.

    WS_EX_CONTROLPARENT would make more sense to me as WS_EX_CONTROLGRANDPARENT – because what it seems to mean is that its children have child controls too.

  10. Ben Cooke says:

    This seems strange to me since the pre-W2K dialogs were thinner (and non-resizable?) and W2K grew them to accommodate the new bar. Shifting the contained window would have left the application with the same amount of space but in a different place, and since the controls inside are relative to the embedded dialog this would have had no ill-effect.

    Instead, the contained window either has a space to its right or is made larger (I’ve never tried to find out) which I would expect causes more rather than less problems than the alternative… either the dialog is wider than it thought it would be, or the controls which previously lined up with the stock controls are now smooshed over to the left under the places bar.

    Making the dialogs resizable was an interesting choice given that dialog boxes conventionally are NEVER resizable and NEVER have toolbars (which the file dialog also does) but I admit it’s a good feature here. Ideally, there wouldn’t be an "Open" or "Save" dialog at all, but we don’t live in an ideal world. ;)

  11. Adrian says:

    Raymond, thanks for covering this topic (and in advance for the upcoming dialog topics). I spent a lot of time figuring out how Windows dialog behavior is a complex interaction between a hidden modal loop, DefWindowProc, DefDialogProc, and a few of these more obscure message.

    I hope your dialog box posts will cover DeferWindowPos (and related functions). I made a dialog box replacement that handles layout of its children dynamically rather than relying on fixed values in a resource. These containers may be nested (using WS_EX_CONTROLPARENT). I tried to make them more efficient by replacing the SetWindowPos calls with the defered variety. When I call EndDeferWindowPos, the children are sized and moved as expected, but they do not receive WM_SIZE messages. Without those, the recursion is broken and the grandchildren don’t get resized and repositioned. Is supressing the WM_SIZE notifications an intentional and undocumented optimization of EndDeferWindowPos?

  12. Mat Hall says:

    I much preferred the old 3.1-style open/save dialogs, with the tree view and file list. The newer ones have several broken features, some of which I list below:

    * They default to Small Icons view, don’t remember window resizing, etc.

    * File format preferences are also not remembered. (This can be fixed app-side, but I think this should be the dialog’s job.)

    * All columns in the file/folder display area are resized to fit the longest file name, meaning that on occasion you can only see 6 or so files/folders.

    * The lack of a tree view means that sometimes it’s hard to be sure which directory you’re in — all my VB projects have the same sub-folder structure, so without popping back a few levels I can’t be sure I’m in the right "Resources" folder or whatever. (The 3.1 dialogs showed the path in addition to the folder tree, so it was easy to see where you were.)

    (Back in the olden days, the Acorn Archimedes had a novel alternative to the Open/Save dialogs. Opening was always accomplihed by double-clicking a document or dragging the icon onto the window, and saving just presented you with an icon to drag in to the folder of your choice.)

  13. Norman Diamond says:

    7/30/2004 11:46 AM Ben Cooke

    > Making the dialogs resizable was an

    > interesting choice given that dialog boxes

    > conventionally are NEVER resizable

    Making dialogs resizable was an absolute necessity. Another necessity is also absolute though rarer, and has not been done yet: give them scroll bars when necessary. Sometimes dialog boxes contain information that the user wants to read, and sometimes these are the only way for the user to get it.

  14. asdf says:

    Speaking of resizable dialogs, I finally uploaded my resizable message box stuff after 8 months:

    http://www.kkow.net/etep/code/mb/ and

    http://www.kkow.net/etep/code/assert.html

    for sample customization. Pass it on…

  15. As an accommodation to older tools.

Comments are closed.