November 22nd, 2012

The resource compiler will helpfully add window styles for you, but if you're building a dialog template yourself, you don't get that help

A customer was having trouble with nested dialogs. They were doing something very similar to a property sheet, with a main frame dialog, and then a collection of child dialogs that take turns appearing inside the frame dialog based on what the user is doing. The customer found that if they created the child dialogs with the Create­Dialog­Param function, everything worked great, but if they built the template at run-time, keyboard navigation wasn’t working right. Specifically, one of their child dialogs contained an edit control, and while you could put focus on it with the mouse, it was not possible to tab to the control. On the other hand, a resource template didn’t have this problem. Tabbing in and out worked just fine.

There is logically no difference between a resource-based dialog template and a memory-based one, because the resource-based one is implemented in terms of the memory-based one.

The real problem is the memory-based template you created differs somehow from the one the resource compiler generated.

One way to identify this discrepancy is simply to do a memcmp of the two dialog templates, the resource-based one and the memory-based one, and see where they differ. After all, if you want to know why your template doesn’t match the one generated by the resource compiler, you can just ask the resource compiler to generate the template and then compare the two versions.

Instead of explaining this, I decided to invoke my psychic powers.

My psychic powers tell me that you neglected to provide the WS_TAB­STOP style to the edit control when you created your in-memory template. (You probably didn’t realize that you needed to do this, because the resource compile adds that style by default.)

When you use the resource compiler to generate a dialog template, it sets a bunch of styles by default, depending on the type of control. For example, EDIT­TEXT says “If you do not specify a style, the default style is ES_LEFT | WS_BORDER | WS_TABSTOP.”

Not mentioned is that the default style is in addition to the defaults for all controls: WS_CHILD | WS_VISIBLE.

If you want to turn off one of the default styles for a control, you do so with the NOT keyword. For example, if you write

   EDITTEXT IDC_AWESOME, 10, 10, 100, 100, ES_MULTILINE | NOT WS_VISIBLE

the resource compiler starts with the default style of

dwStyle = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | WS_TABSTOP;

then it adds ES_MULTI­LINE:

dwStyle |= ES_MULTILINE;
// dwStyle value is now
// WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | WS_TABSTOP | ES_MULTILINE

and then it removes WS_VISIBLE:

dwStyle &= ~WS_VISIBLE;
// dwStyle value is now
// WS_CHILD | ES_LEFT | WS_BORDER | WS_TABSTOP | ES_MULTILINE

which is the final style applied to the control.

The resource compiler is trying to help you out by pre-setting the styles that you probably want, but if you don’t realize that those defaults are in place, you may not realize that you need to provide them yourself when you don’t use the resource compiler. Maybe it was being too helpful and ended up resulting in helplessness.

The customer was kind enough to write back.

Thanks! That did the trick.

For completeness, the default dialog style is WS_POPUP­WINDOW = WS_POPUP | WS_BORDER | WS_SYS­MENU. If you have a custom font, then you also get DS_SET­FONT, and if you have a caption, then you get WS_CAPTION.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.