20.2.5 Custom Controls

If you have developed custom controls, you can place the code for the controls in a dynamic-link library. You can then use Dialog Editor to access the library to display your custom control during a dialog box editing session. For more information about Dialog Editor, see its online help file.

For your control library to be used by Dialog Editor and other applications, you will need to define and export the functions described in this section.

In the following function descriptions, Class is used as a placeholder for the class name of your control. The name of your custom control is the same name a user of Dialog Editor specifies for the control. The control name is typically the same as the module name of the dynamic-link library, but not necessarily.

Structure definitions, such as for CTLINFO, and constants that define the interface of a custom control by using Dialog Editor, are provided in the CUSTCNTL.H header file.

This section describes six functions that your custom-control library must export. The library should export these functions by ordinal value, as shown in the following list:

Exported function Ordinal value

WEP Any number except 2 through 6
ClassInit or LibMain Not required
ClassInfo 2
ClassStyle 3
ClassFlags 4
ClassWndFn 5
ClassDlgFn 6

For example, the functions exported by the Rainbow custom-control example are declared in the RAINBOW.DEF file as follows:

EXPORTS
   WEP             @1 RESIDENTNAME
   RAINBOWINFO     @2
   RAINBOWSTYLE    @3
   RAINBOWFLAGS    @4
   RAINBOWWNDFN    @5
   RAINBOWDLGFN    @6

For more information about the LibMain function, see Section 20.3.1.1, “Initializing a Dynamic-Link Library.” For more information about the WEP function, see Section 20.3.1.2, “Terminating a Dynamic-Link Library.”

Following are descriptions of the custom-control functions:

HANDLE FAR PASCAL ClassInit(hinst, wDataSegment, wHeapSize, lpszCmdLine)

The ClassInit function takes care of all the initialization necessary to use the dynamic-link control library. Your assembly-language entry point to the library usually calls this function. In addition to saving the library instance handle by using a global static variable, this function should register the control window class and initialize the local heap by calling the LocalInit function, if your assembly-language entry routine does not initialize the local heap. If you link the custom-control dynamic-link library with LIBENTRY.OBJ instead of providing your own assembly-language entry point, this function is named LibMain. For more information about dynamic-link-library entry points and initialization, see Section 20.3.1.1, “Initializing a Dynamic-Link Library.”

Parameter Type Description

hinst HANDLE Identifies the instance of the library.
wDataSegment WORD Specifies the library data segment.
wHeapSize WORD Specifies the default library heap size.
lpszCmdLine LPSTR Specifies the initial command-line arguments.

The return value is a library-instance handle if the function registers the control class and completes the initialization. Otherwise, the return value is NULL.

HANDLE FAR PASCAL ClassInfo( )

The ClassInfo function provides the calling process with basic information about the control library. Based on the information returned, the application can create instances of the control by using one of the supported styles. For example, Dialog Editor calls this function to query a library about the different control styles it can display.

This function has no parameters.

The return value identifies a CTLINFO structure if the function is successful. This information becomes the property of the caller, which must explicitly release it by using the GlobalFree function when the structure is no longer needed. If there was insufficient memory to allocate and define this structure, the return value is NULL.

The CTLINFO structure defines the class name and version number. The CTLINFO structure also contains an array of CTLTYPE structures, each of which lists commonly used combinations of control styles (called variants) with a short description and suggested size information.

Following are the structure definitions and their related values:

/* general style & size definitions */

#define CTLTYPES 12
#define CTLDESCR 22
#define CTLCLASS 20
#define CTLTITLE 94

/* control information structure */

typedef struct {
    UINT        wType;
    UINT        wWidth;
    UINT        wHeight;
    DWORD       dwStyle;
    char        szDescr[CTLDESCR];
} CTLTYPE;

typedef struct {
    UINT        wVersion;
    UINT        wCtlTypes;
    char        szClass[CTLCLASS];
    char        szTitle[CTLTITLE];
    char        szReserved[10];
    CTLTYPE     Type[CTLTYPES];
} CTLINFO;

typedef CTLINFO *   PCTLINFO;
typedef CTLINFO FAR *LPCTLINFO;

For full descriptions of the CTLTYPE and CTLINFO structures, see the Microsoft Windows Programmer's Reference, Volume 3.

BOOL FAR PASCAL ClassStyle(hWnd, hCtlStyle, lpfnStrToId, lpfnIdToStr)

Dialog Editor calls the ClassStyle function to display a dialog box to edit the style of the selected control. When this function is called, it should display a modal dialog box in which the user can edit the CTLSTYLE members. The user interface of this dialog box should be consistent with that of the predefined controls that Dialog Editor supports.

Parameter Type Description

hWnd HWND Identifies the parent window of the dialog box.
hCtlStyle HANDLE Identifies the CTLSTYLE structure.
lpfnStrToId LPFNSTRTOID Points to a function supplied by Dialog Editor that converts a string to a numeric identifier.
lpfnIdToStr LPFNIDTOSTR Points to a function supplied by Dialog Editor that converts a numeric identifier to a string.

The return value is nonzero if the CTLSTYLE structure was changed. Otherwise, it is zero.

The CTLSTYLE structure specifies the attributes of the selected control, including the current style flags, location, dimensions, and associated text. The CTLSTYLE structure has the following format:

/* control style structure */

typedef struct {
    UINT        wX;
    UINT        wY;
    UINT        wCx;
    UINT        wCy;
    UINT        wId;
    DWORD       dwStyle;
    char        szClass[CTLCLASS];
    char        szTitle[CTLTITLE];
} CTLSTYLE;

typedef CTLSTYLE *   PCTLSTYLE;
typedef CTLSTYLE FAR *   LPCTLSTYLE;

For a full description of the CTLSTYLE structure, see the Microsoft Windows Programmer's Reference, Volume 3.

Dialog Editor keeps track of user-specified control identifiers and their corresponding symbolic-constant names, maintaining them in a header file that is included when the application is compiled. The control-style function accesses this information by using the functions pointed to by the lpfnStrToId and lpfnIdToStr parameters. The parameters point to two function entry points within Dialog Editor itself. To call these functions, you should prototype them as follows:

/* ID to string translation function prototypes */

typedef WORD   (FAR PASCAL *LPFNIDTOSTR) (WORD, LPSTR, WORD);
typedef DWORD  (FAR PASCAL *LPFNSTRTOID) (LPSTR);

The Dialog Editor entry-point function pointed to by the lpfnIdToStr parameter allows you to translate the numeric identifier provided in the CTLSTYLE structure into a text string containing the symbolic-constant name defined in the header file. This text string can then be displayed in place of a numeric value in your custom control's style dialog box. The first parameter is the control identifier. The second parameter is a long pointer to a buffer that receives the string, and the third parameter is the maximum length of that buffer. The function pointed to by lpfnIdToStr returns the number of characters copied to the string. If the function returns zero, it failed.

The function pointed to by lpfnStrToId works in reverse, translating a string to a numeric identifier. The function accepts the string containing a symbolic-constant name and returns the corresponding control identifier. If the low-order word of the return value is nonzero, the high-order word contains the control identifier, which you can use to update the wId member of the CTLSTYLE structure. If the low-order word of the return value is zero, the constant name was undefined and the ClassStyle function should generate an error message.

Typically, whenever ClassStyle is called it will call the function pointed to by lpfnIdToStr, passing it the value contained in the CTLSTYLE member wId. If the function pointed to by lpfnIdToStr returns a value greater than zero, ClassStyle displays the resulting string in an edit control so the user can change it. Otherwise, it displays the numeric value of the control identifier. If the user changes the edit field, ClassStyle calls the function pointed to by lpfnStrToId to verify that the string contains a valid symbolic-constant name and replaces the CTLSTYLE member wId with the high-order word of the return value.

BOOL FAR PASCAL ClassDlgFn(hDlg, wMessage, wParam, lParam)

The ClassDlgFn function is the dialog box procedure responsible for processing all the messages sent to the style dialog box. The style dialog box is invoked when the ClassStyle function is called. The ClassDlgFn function should enable the user to edit selected portions of the CTLSTYLE structure passed to the ClassStyle function.

Parameter Type Description

hDlg HWND Identifies the window that will receive the message.
wMessage WORD Specifies the message.
wParam WORD Specifies 16 bits of additional message-dependent information.
lParam LONG Specifies 32 bits of additional message-dependent information.

The return value is nonzero if the function is successful. Otherwise, it is zero.

WORD FAR PASCAL ClassFlags(dwFlags, lpStyle, wMaxString)

The ClassFlags function translates the specified class style flags into a corresponding text string for output to a resource-definition (.RC) file. This function should not interpret the flags contained in the high word, since these are managed by Dialog Editor. Note that you should use the same control style definitions that are specified in your control header file.

Parameter Type Description

dwFlags DWORD Specifies the current control flags.
lpStyle LPSTR Points to a buffer that will receive the style string.
wMaxString WORD Specifies the maximum length, in bytes, of the style string.

The return value is the number of characters copied to the buffer identified by the lpStyle parameter, if the function is successful. Otherwise, the return value is zero.

LONG FAR PASCAL ClassWndFn(hWnd, wMessage, wParam, lParam)

The ClassWndFn function is the window procedure responsible for processing all the messages sent to the control.

Parameter Type Description

hWnd HWND Identifies the window that will receive the message.
wMessage WORD Specifies the message.
wParam WORD Specifies 16 bits of additional message-dependent information.
lParam LONG Specifies 32 bits of additional message-dependent information.

The return value indicates the result of the message processing and depends on the message sent.