Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Programmer's Bookshelf


JUN94: PROGRAMMER'S BOOKSHELF

PROGRAMMER'S BOOKSHELF

Custom Controls and Windows Programming

Michael Floyd

When it comes to the popularity of custom and visual controls, there's no mystery. As a custom-control developer, you can create a control that is used in the Visual Basic (VB) environment just as any standard control is used. When loaded, the control appears on the tool bar. In Visual Basic, you can edit the control's properties and event code just as with standard controls--extending, in effect, the VB environment.

Think of custom controls as data encapsulation on a grand scale. A custom control is an object contained within a .VBX file--it has a predefined set of features and a clearly defined interface to that feature set. Yet developing custom controls adds a level of complexity and isn't without drawbacks. Although a .VBX is a DLL, developing a custom control is far more involved because a custom control is self contained--it must encapsulate the machinery required to operate in both the application space and the visual-design environment. From the programmer's perspective, there are compatibility issues between versions of the VB API. And you must determine whether your controls need to be visual, nonvisual (for use only in an application), or both.

Windows Programming Power with Custom Controls by Paul Cilwa and Jeff Duntemann offers insight into these problems and provides useful tools for the custom-control developer. Windows Programming Power with Custom Controls takes a workbench approach to developing custom controls. First, it walks you through the development of a generic control, then guides you through new concepts while creating more interesting and useful controls.

Tools for Development

If you plan on creating the visual versions of the controls in the book, you'll need to get either the Visual Basic 3.0 Professional Edition, which includes the Control Development Kit (CDK), or the Visual Control Pack. The CDK, a C-based SDK, contains files needed for writing VBXs, as well as the visual layer required by the controls. You'll also need a C compiler and linker capable of generating a Windows DLL. Duntemann and Cilwa suggest Microsoft C 6.x, Borland or Turbo C++, or Symantec C++. Because the authors use Borland C/C++, you'll need to make some changes to the modules to get these controls to compile under other development environments. An obvious example is the author's use of Borland's #pragma argsused to eliminate certain warning messages when compiling. This doesn't appear in the book's listings, but is in the source code supplied on the accompanying disk. The Microsoft equivalent is #pragma warning.

When I loaded the .RC files into AppStudio, the error "undefined keyword or key name VOS__WINDOWS16" appeared. This is a constant specified with the VERSIONINFO statement. Including VER.H in the resource-definition file solved the problem.

Since the Borland compiler doesn't directly support the creation of .VBX files, you must define your project as a .DLL and rename the output file using a .VBX extension. The authors provide a utility DLL2VBX to aid in this. Interestingly, Borland C++ 4.0 allows you to rename the file's extension from within the IDE. I tried this, but the compiler bombed out on the build with the cryptic error message: "IDE error." I solved this problem by restoring the file's extension to .DLL.

A Bare-Bones Control

The book's first project creates a "skeleton" control that implements the basic functionality of a custom control. The skeleton is used in later chapters as a basis for creating more-interesting controls. Upon finishing this chapter, you'll know how a generic custom control performs its job. You'll also have a functional custom control that you can use as a custom-control template in your own development. The skeleton control is minimal by design, so you may want to enhance this template for real work.

In keeping with a modular design, the skeleton control is broken into several components. INTERNAL.H is a private #include file that supplies the constants and prototypes used by the skeleton control. SKELETON.H contains the #defines for message IDs and data structures used by a control. Because the skeleton control doesn't define any messages, this file is initially empty. The SKELETON header file is renamed and used in subsequent chapters.

MAIN.C is where the Windows message handler resides. In this respect, this module looks like a typical Windows application. However, there are some differences in how a custom control handles certain messages. For instance, a control can respond to both Windows messages and messages generated by visual development environments like VB. The difference is that VB messages refer to properties and events. The discussion here glosses over this point, but is still better than a blow-by-blow description of the source code. For example, the authors provide useful tidbits, such as how to use static near to simulate function nesting (a feature supported by languages such as Borland Pascal). Duntemann and Cilwa also point out that DLLs require the large memory model. This is, in fact, a requirement of C++. However, you can still make intrasegment calls near.

VISUAL.C, an optional module that supports controls in a visual environment, is a fine introduction to the inner workings of the VB environment. This module zeros in on properties, methods, and events. Properties help define how a visual control will appear to the environment. The discussion of properties primarily refers to custom properties. It's worth noting that VB also supplies a library of standard properties and events which help to define a uniform interface to visual controls so that you don't have to reinvent the wheel. When you can, use them. To implement a standard property, simply include the appropriate constant in the property table.

It's interesting that the authors decide to set up properties at compile time. Typically when a control is loaded, it's registered, and the MODEL control data structure is initialized. Standard programming practice is to store a visual control's property-name strings in a resource pool to be loaded when the control is initialized. This added overhead can slow things down. Setting up properties at compile time can significantly improve performance.

One topic the authors skim over is the MODEL structure, merely mentioning that MODEL is a sort of master structure that points to all other structures in the control. This is partially true. However, MODEL contains information about the control's general behavior, window styles, class names and styles, and so on. Understanding this is key to the behavior of your control. Figure 1 recreates the MODEL structure as defined in VISUAL.C. VB_VERSION is an unsigned int defined in VBAPI.H, and specifies the version of VB being used. Next, two flags are listed. The MODEL_fFocusOk flag allows the control to receive the focus at run time, and MODEL_fArrows allows the arrow keys on the keyboard to be used within the control. Normally, arrow keys are used to move between controls. PCTLPROC specifies the address of the control procedure. CS_VREDRAW, CS_HREDRAW, and WS_BORDER are window styles. The rest of the structure is as advertised. The Control Development Guide documents the MODEL data structure.

Other modules include DIALOG.C (to provide support for dialog boxes), PAINT.C (paint routines for displaying a control), and HELP.C (for online help).

Other Controls

Subsequent chapters begin the process of creating something real. First, a panel control is created. The panel control is a customization of the skeleton control and shows how you can give a three-dimensional look to controls by adding sunken and raised bevels. The control also supports flood filling within the beveled control. Because the panel control is similar to that in VB, the authors reasoned that it was not necessary to support the visual environment hooks. Therefore, the VISUAL module is not included for this control and it can only be used within a standard Windows app. I found this surprising since the authors hint elsewhere in the book that other visual environments will soon support visual controls.

On the upside, I was pleasantly surprised by the inclusion of a Pascal unit that allows the panel control to be used in Borland Pascal for Windows applications.

Other controls created in the book include a virtual list-box control which shows how you can extend list boxes to contain up to 32 Kbytes; a database Browser control that allows you to browse records in a database; a page-list control that allows the control user to select a document page from a list of page icons; a text-file viewer; and a text-file editor based on the file-viewer control. Throughout these sections, a number of useful embellishments are provided, including the use of offset text to highlight key points and the use of text boxes to highlight some rather interesting asides. One text box, for example, explains how Borland's Resource Workshop extends the CTLINFO data structure, which defines the class name and version number for a custom control. 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 information about the suggested size. Borland redefines this structure as RWCTLINFO in CUSTCNTL.H. The authors have created their own, called CONTROLINFO. These and other tidbits are sprinkled throughout the book.

Likewise, every good book has a hidden gem. In Windows Programming Power, this jewel is the .INI file manager control, called "IniData." This VB-only control allows users to view, process, and manage Windows .INI files--a task not easily accomplished in VB. One unique feature of this control allows you to encrypt key values to prevent users from reading or modifying an application's .INI file. The algorithm uses simple substitution, where each plaintext character is replaced by a ciphertext character. Most substitution algorithms are easy to break because they merely shift to the right a specified number of characters to obtain the encrypted text. Such algorithms do nothing to hide the frequency of characters. Instead, this algorithm uses a substitution table to supply the encrypted text characters. The algorithm is not sophisticated. It converts all letters to upper case and only works with alphabetic characters; nonalphabetic characters are passed through. However, the purpose here is to prevent a user from accidentally blowing away a sensitive section of the .INI file.

Missing in Action

The Microsoft approach to developing custom controls is through Visual C++ and the Microsoft Foundation Class (MFC) Library. MFC 2.5 emulates portions of VB to allow an MFC application to use .VBXs. If you're looking for help in this area, look elsewhere. This topic is missing, but not missed. The authors' SDK-style approach to developing custom controls precludes any discussion of the MFC approach. And with OLE Custom Controls on the horizon, future support of .VBXs in MFC is uncertain.

The three levels of support for custom controls coincide with the three versions of VB. Each version adds support for new features, and older versions can be viewed as a subset of subsequent versions. Visual C++ only supports VB 1.0-compliant controls. Naturally, you may have to support multiple versions. It's possible to develop a single custom control that behaves correctly in each host environment. This is detailed in the Control Development Guide. Unfortunately, the book does not cover this.

Creating custom-control wrappers is another topic you might find useful. A wrapper is basically a custom control that provides a high-level interface to DLL functions. Many developers who have created DLLs have the potential to convert these to custom controls. Even if the DLL has no UI components, you can create an invisible control which displays its bitmap at design time, but is hidden at run time.

Conclusion

Windows Programming Power with Custom Controls is not a replacement for the CDK documentation. In fact, you'll want to keep the Custom Control Reference and the Control Development Guide nearby. Windows Programming Power does provide a generic custom control which can serve as a starting point for any custom control, and it gives you useful controls that can be used as-is, or embellished for your specific needs. The authors have designed this book so that the learning process is incremental--each new control introduces a new concept while leveraging concepts built in previous chapters. Within this process, Duntemann and Cilwa add their own unique insights into the design and development of custom controls. In the end, you'll walk away with a better understanding of custom controls and some new and useful tools.

Windows Programming Power with Custom Controls

Paul Cilwa and Jeff Duntemann

Coriolis Group Books, 1994, 480 pp.

$39.95

ISBN 1-883577-00-4


Figure 1: The MODEL data structure.

MODEL Model =
     {
     VB_VERSION,
     MODEL_fFocusOk | MODEL_fArrows,
     (PCTLPROC) CtlProc,
     CS_VREDRAW | CS_HREDRAW,
     WS_BORDER,
     sizeof (VBDATA),
     8000,
     NULL,
     NULL,
     NULL,
     Properties,
     Events,
     IPROPINFO_STD_NAME,
     IPEVENTINFO_STD_CLICK,
     -1
     };

Copyright © 1994, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.