Visual Basic

Custom Controls

Custom controls are a good example of base code that can be reused time and time again. Tired of having to code a GotFocus event for every text box to highlight its contents? Why not create a custom TextBox control that handles its own GotFocus event but in all other respects acts like a normal text box? The ActiveX Control Interface wizard will generate up to 95 percent of the code you need, leaving you with only a few lines of code to write yourself. A custom control that was generated from this wizard is included with the sample code for this chapter. If you examine the code closely, you will see that the ActiveX Control Interface wizard generated all but four lines!

The sample control is very simple-it simply extends an existing property of another control. However, the wizard makes it equally simple to add custom properties of your own, such as numeric formatting and data validation. For more detailed information on creating custom controls, see Chapter 14. Chapter 6 also provides some information on creating a Year 2000_compliant TextBox control.


A key area with base code that is often overlooked is that of documentation. It's no good having a library of 20 code modules with hundreds of functions in them if developers have to search through all of them each time they want to see if a common routine already exists to do what they want.

Similarly, if the parameters and return values are not documented, developers might not be able to work out how to call a particular routine or how to interpret the results. When this is the case, the developers will invariably end up writing their own versions of the routine. Consider the following infrastructure routine's interface:

GetUserPrivilegeFlags(nUser As Long, _
                        nPrivFlags() As Integer, _
                        bForcePriv As Boolean, _
                        Optional nForcePrivNo As Integer)

I know that if I were not intimately familiar with this routine I would be tempted to write my own version. For example, is the array one-dimensional or multi-dimensional? Do I need to pass the array with values or an uninitialized array? How on earth are the last two parameters used? You can see the dilemma. The interface is of paramount consideration because it has the potential to scare off any potential users of the routine. Contrast the code above to the same fragment rewritten below:

GetUserPrivilegeFlags(ByVal lUserId As Long, _
                        ByRef nPrivFlags() As Integer, _
                        ByVal bGiveSpecificPrivilege As Boolean, _
                        Optional ByVal nSpecificPrivId As PRIVILEGE)

By using the ByVal and ByRef keywords, it is clear what is expected and what is returned. The argument names have been modified to be more meaningful, and the last parameter, nSpecificPrivId, has been typed so that a drop-down list of values will be displayed to the user, alleviating any ambiguity for this parameter's value. However, we still have the problem of not knowing the format of the exact requirement for nPrivFlags. This problem can be solved by using the Procedure Attributes item in the Tools menu. This allows you to enter a description that appears in the Object Browser when the procedure is selected.