November, 1995 - Vol. 2 No. 11
In the accompanying article, Using OWL to create custom controls we mention that there are
very few good resources for information about writing custom controls.
If you're looking for information about writing controls
that are compatible with Resource Workshop, you'll find
even fewer. Here, we'll review the functions you have to
create when building your own custom controls, as well as the
special ListClasses() function that Resource Workshop
supports.
A dialog editor will call the Info() function to retrieve
a CTLINFO data structure that describes the characteristics
of the custom control. This data structure (defined in the run-time
library file CUSTCNTL.H) contains information such as
This information allows the dialog editor to display appropriate information about the control at design time.
The prototype for the Info() function is straightforward,
as you can see:
HGLOBAL CALLBACK Info(void);
When you create this function, it needs to call the GlobalAlloc()
API function to allocate a block of memory, fill in the appropriate
locations in a CTLINFO or RWCTLINFO data structure,
and then return an identifier for this block of memory. (The RWCTLINFO
data type extends the CTLINFO type to include information
necessary for Resource Workshop to display a toolbox icon for
the control. This type definition also appears in the CUSTCTRL.H
file.)
The Flags() function allows you to determine how the
dialog editor will translate the style information for a control
into text that the editor can store in an RC file. (If you want
to view this type of information, locate an RC file in a BC++
project window, right-click it, and choose Text Edit from the
View submenu.) The prototype for the Flags() function
is
UINT CALLBACK Flags(DWORD dwFlags, LPSTR lpStyle, UINT wMaxString);
Let's look at each of the parameters.
The dwFlags parameter represents one of the styles that
your control specified in the Info() function. (Each
control style may store its text description in a different way.)
The lpStyle parameter identifies a block of memory where
you can insert the translated text for the control's style
information. The last parameter, wMaxString, tells you
how big this block of memory is so you won't accidentally
write data past the end of the block.
The dialog editor will call the Style() function in your control's DLL when you attempt to edit the control. For example, when you double-click a control in Resource Workshop, it displays a dialog box that you can use to manipulate the characteristics and style of the control.
The prototype for the Style() function is somewhat complex,
as shown here:
BOOL CALLBACK Style(HND hWnd, HGLOBAL hCtlStyle, LPFNSTRTOID lpfnStrToId, LPFNIDTOSTR lpfnIdToStr);
For the return value, you'll specify TRUE if the user makes valid changes to the control and FALSE if the user abandons the changes or enters invalid data.
The hWnd parameter, contrary to what you might expect, isn't an identifier for the control's window. Instead, it's an identifier for the parent window that will display the dialog box. (For example, Resource Workshop calls this function and passes the identifier for the Resource Workshop main window.)
The hCtlStyle parameter is an identifier you can use to access a block of memory that contains a CTLSTYLE or RWCTLSTYLE structure. The CTLSTYLE data structure (also defined in CUSTCNTL.H) contains size, position, and style information for the control, as well as descriptive text strings that contain the control's class name and its caption, if any. The RWCTLSTYLE data structure contains these same elements plus an optional block of up to 255 bytes that you can use to contain additional information that's common to all controls of this class.
The last two parameters, lpfnStrToId and lpfnIdToStr,
are function pointers that address two functions that you can
use to convert a text string into a resource ID and vice versa.
If Resource Workshop can locate an RH file that associates specific
resource IDs with text strings using #define directives,
you can pass the control's resource ID to the function
that lpfnIdToStr identifies, and it will copy the text
to a buffer. You can display the text from that buffer to help
the user identify the control.
Of the four functions we're examining, the ListClasses() function is unique to controls that support Resource Workshop. The other three functions are necessary for both Resource Workshop and Microsoft Dialog Editor. The ListClasses() function performs one important task: It identifies a custom control DLL as one that supports the Resource Workshop versions of the Style() and Info() functions' data structures.
The return value from the ListClasses() function is an identifier for a block of memory that contains one or more sets of pointers to the three functions we just mentioned and text strings that identify the corresponding custom control class. For example, if you define two custom control classes in a DLL, that DLL should contain two Info() functions, two Flags() functions, and two Style() functions. Each function corresponds to one of the two control classes.
However, you'll need to define only one ListClasses()
function. This one function will return an identifier for the
block of memory that contains the addresses of the functions and
the class name strings for both control classes in a CTLCLASSLIST
data structure. As with the other information, you'll find
the definition for the CTLCLASSLIST type in the CUSTCTRL.H
file.
If you have version 4.02 of Borland C++, you'll find the file CUSTCNTL.TXT in the \BC4\DOC subdirectory. This file describes some of the basics of creating custom controls that we've discussed here. Unfortunately, it doesn't go into great detail.
In contrast, Windows Programming Power with Custom Controls,
by Paul Cilwa and Jeff Duntemann (Coriolis Group Books), is a
comprehensive tutorial on creating all sorts of custom controls.
This book doesn't focus on Resource Workshop compatibility
the way the CUSTCNTL.TXT file does, but it goes into much greater
detail about Windows custom controls in general.
Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.