Introduction
The Dialog Editor Controls Pack, by Simon Whiteside, is a set of Windows custom controls that you can position on your own application windows to create a built-in dialog box editor. A dialog box editor implemented as a Windows custom control is a new concept and one that allows maximum flexibility in integration. To get up and running, all you have to do is load the custom controls and then call CreateWindow() once for the DLGEDIT_CLASS and once for the DLGPAL_CLASS. Figure 1 shows the dialog box editor with a work-in-progress in a scenario where the dialog box control has been sized to fill the entire window.
As a Windows developer, you've probably used dialog editors since your first day with the SDK. However, the Windows SDK Dialog Editor (dlgedit.exe) cannot be redistributed with your application. Furthermore, customers can be expected to balk at having to buy and install an SDK just to have dialog box editing capabilities. The Dialog Editor Controls Pack lets you seamlessly integrate such capabilities. It includes Windows custom controls that provide a dialog editor user interface along with a corresponding message programming interface.
A Dialog Editor Control and Palette Control
Whiteside's pack provides two Windows custom controls to help you build dialog editors for your tools (see Figure 1). You can employ these Windows custom controls in many ways: from raw dialog definition editors all the way up to code generators. The principal custom control is the "Dialog Editor control" (or DLGEDIT). This custom control has its own programming interface, which allows you to add or modify the controls it owns. It also has a user interface that allows the user to move and resize its controls.
The pack also supplies a "Palette control" (or DLGPAL) which understands the programming interface to the dialog editor. You can use this control to provide a customizable "tool palette" from which the user can drag controls to be added to the dialog editor (see Figure 2). The palette control can handle any mix of up to 100 controls simultaneously.
The controls are managed via Windows messages that use the structures and messages defined in dlgedit.h (supplied with the pack). This file also contains macros, similar to those in windowsx.h, that make sending the messages easier. Each class resides in its own DLL: DLGEDIT in dlgedit.dll and DLGPAL in dlgpal.dll.
You can use Loadlibrary() to load the DLLs, or you can link to the import libraries dlgedit.lib and dlgpal.lib. The functions DeLoad() and DpLoad() initialize dlgedit.dll and dlgpal.dll, respectively.
DLGEDIT Message Interface and Data Structures
As mentioned above, the DLGEDIT control can be completely managed through a message-level interface. Figure 3 lists all of the messages supported by DLGEDIT. You can either call SendMessage() directly or else invoke a C macro that does this for you, as shown below:
#define DeFindControl(hctl,flag,lparam)\ SendMessage(hctl,DE_FINDCONTROL,flag,lparam)The DE_ADDCONTROL, DE_SETCONTROLINFO, and DE_GETCONTROLINFO messages work with the complete definition of a control and so need more data than can fit in lParam and wParam. These three messages all pass a pointer to a CONTROLINFO structure in the lParam (see Figure 4). The CONTROLINFO structure contains basic resource information such as location, size, control ID, style bits, and more. I will describe later how the DLGPAL control sends a DE_ADDCONTROL message each time the user does a drag-and-drop from the palette on to the dialog editor. The DLGEDIT control can handle up to 100 controls.
The other messages specific to individual controls (DE_DELETECONTROL, DE_GETFOCUSINDEX, and DE_FINDCONTROL) all operate on simple control IDs rather than CONTROLINFO structures.
Some messages refer more to global parameters in DLGEDIT than to individual controls. DE_GETCOUNT returns the total number of controls. DE_SETGRID, DE_GETGRID, and DE_ISGRIDON allow you to easily customize a grid overlay. The grid overlay makes it easier for the user to visually line up controls. You can force all new controls to align ("snap" in CAD terminology) with grid marks by using DE_SETSNAPON. You can discover the snap state with DE_ISSNAPON.
The DE_SETTEST message switches the dialog editor control into or out of test mode. In test mode, the entire set of controls becomes active, as if it were under the control of a standard Windows dialog box callback. Testing helps you examine the look and feel of a dialog before writing the support code.
Neither DE_ALIGNCONTROLS nor DE_SIZECONTROLS is implemented in version 1.00. These messages are intended to act on groups of selected controls, but the current version supports only single selection rather than multiple selection.
DLGPAL Message Interface and Data Structures
The dialog palette is designed to interact with the dialog editor. It presents the user with a palette from which controls can be dragged and dropped onto the editor. When the user drops a control on the dialog editor, the palette sends the editor a DE_ADDCONTROL with the details stored in the CLASSINFO structure held for the item in the palette.
Most dialog editing applications can work just fine with an essentially fixed palette. However, a rich message interface allows for dynamic reconfiguration of the palette (see Figure 5). The only message that you're required to use is DP_ADDCLASS. Each invocation of this message adds another control to the DLGPAL.
The DP_ADDCLASS, DP_GETCLASSINFO, and DP_SETCLASSINFO messages all use the CLASSINFO structure pointer as the lParam. The CLASSINFO structure (see Figure 6) is an abbreviated version of the familiar CONTROLINFO structure used in the DLGEDIT control.
The DP_FINDCLASSINDEX and DP_REMOVECLASS messages operate on an ordinal value, similar to a control ID, indicating the logical position of a control in the DLGPAL.
Last, DP_GETCOUNT and DP_GETITEMSIZE return the number of items currently on the DLGPAL and the dimensions of each item, respectively. All items in the DLGPAL are expected to be squares of the same size square.
Putting It All Together
The Dialog Editor Controls Pack includes a complete C source sample application. The sample application begins in WinMain() by calling DpLoad() and DeLoad() to initialize the DLLs. Next, it creates the main window, which is where all controls will be appearing. Afterwards, it enters the familiar GetMessage() and DispatchMessage() loop you might expect in any Windows application.
The WM_CREATE event appears soon after and is dispatched to the application function OnCreate(). This function in turn creates a child window for the DLGEDIT control. This child window will be overlaid on the main window. OnCreate() also creates a separate pop-up window for the DLGPAL. This pop-up window can float anywhere on the screen and is sized precisely two icons wide by five icons tall (see Figure 2).
Soon after WM_CREATE is processed, a WM_SIZE message appears and the application calls MoveWindow() to stretch the DLGEDIT control to overlay the entire main window. If you have other controls or data to display on the main window, you can size the DLGEDIT to fit a smaller portion of the window. Beyond WM_SIZE and WM_CREATE, you need only craft some small support functions for menu picks you may wish to support. For example, most dialog editors use a "Test" menu pick to toggle the dialog editor into a tryout mode.
The sample application includes source for two other handy utilities you'll want to incorporate: SaveDialog() and Style(). SaveDialog() lets you dump the contents of the DLGEDIT control to .dlg file for easy incorporation into your application. Figure 7 shows the .dlg file generated from the dialog box being edited in Figure 1. Although the sample application calls this from the "File" menu (IDM_SAVE), you can put it on a toolbar or anywhere else.
The Style() function brings up a dialog box that presents edit style flags. The style dialog box is somewhat specific to the type of the currently selected control. Using the style dialog, you can easily change any setting associated with a control, including its dialog ID (see Figure 8).
Documentation, Licensing, and Support
Documentation for this pack is entirely contained in a standard Windows Help file (.hlp). The help file is well-organized and includes full hypertext pointers for every message and data structure relevant to dialog editing. The help file is not intended to be an introduction to general usage of Windows controls. The MS Windows "Guide to Programming" (chapter 8) provides such an introduction.
The Dialog Editor Controls Pack is a shareware product, which means that you can try it before you buy it. If you continue to use it beyond the 30-day evaluation period, you are expected to register the product. This product displays no "nagware" dialogs that beg for registration. Only registered users may redistribute the runtime DLL as part of an integrated product, and registration entitles you to unlimited redistribution of the runtime DLLs.
You can register the pack with a check or money-order for the sum of £30 U.K. This is approximately $50 at current U.S./U.K. exchange rates. If you must register in U.S. funds, please include an extra $7.50 to help pay currency conversion charges. Upon registration, you will receive updates at special rates from the author, who also promises technical support via Internet email for registered users. The author also can be contacted if special versions of the software are required.
Conclusion
For applications ranging from macro languages to full-scale CASE tools, developers have a significant need for incorporating basic dialog editing. Simon Whiteside's Dialog Editor Controls Pack gives you a head start on the dialog editing functionality you need and spares you the task of reinventing the wheel. With the pack, dialog editing can be launched from any application that supports a DLL interface.
Victor R. Volkman received a BS in Computer Science from Michigan Technological University. He has been a frequent contributor to Windows/DOS Developer's Journal since 1990. He is currently employed as Senior Analyst at H.C.I.A in Ann Arbor, Michigan. He can be reached by dial-in at the HAL 9000 BBS (313) 663-4173 or by Usenet mail to sysop@hal9k.com.