What's New
Q & A
Tip Jar
Tips & Tricks
These are brief tips and tricks that can make Visual Basic programming easier.
New Control Usage Numerical Stuff
Starting & Stopping I/O Bug Alerts
Software Engineering Printing System Issues
Graphics Coding Techniques Other Programs
Databases Misc Forms

Software Engineering

Make Irregular Arrays
(By Vitaliy)
In your book Ready-to-Run Visual Basic Algorithms, you write that it is impossible to create irregular and triangular arrays. But you are mistaken, it is possible :) For example:
    Private Type HESH_ITEM
        Key As Long
        ListIndex As Long
    End Type

    Private Type HESH_ITEM_ARRAY
        Element() As HESH_ITEM
    End Type

    Dim HeshTable() As HESH_ITEM_ARRAY

    ReDim HeshTable(5)

    ' Triangular array
    ReDim HeshTable(0).Element(0)
    ReDim HeshTable(1).Element(1)
    ReDim HeshTable(2).Element(2)
    ReDim HeshTable(3).Element(3)
    ReDim HeshTable(4).Element(4)
    ReDim HeshTable(5).Element(5)

    ' Irregular array
    ReDim HeshTable(0).Element(10)
    ReDim HeshTable(1).Element(16)
    ReDim HeshTable(2).Element(2)
    ReDim HeshTable(3).Element(35)
    ReDim HeshTable(4).Element(24)
    ReDim HeshTable(5).Element(5)
Now array HashTable() contains pointers to arrays Element().

Change of the size of this array:

    ReDim preserve HeshTable(10)
    ReDim preserve HeshTable(10).Element(20)
[Note that these are not really arrays. They are arrays of UDTs that contain arrays. A good solution, though! -- Rod]

Don't Trust the Compiler
By Ariel Canievsky

Don't trust in the VB's compiler! I always keep a backup of my projects. I've spoiled a project, so I restored it with the copy. This project contains some pictures. I was going to keep a copy of each picture, but if they're assembled into the FRX binary file it's not necessary to keep an extra copy... is it?

Yes, it is. When I replaced the copies, my forms have lost some pictures. So, don't trust in the assembler, always keep backup.

Getting Started With the API

See Q190000 - HOWTO: Get Started Programming With the Windows API.

Once you've mastered that, you'll want to look at the book Dan Appleman's Visual Basic Programmer's Guide to the Win32 API. [ Amazon.com - Amazon.co.uk]

User Friendly ;-) Popup Menus
By Chris Wagg

Popup Menus are cool for the programmer and the savvy computer user, but some people, especially newer users, sometimes have a difficult time with them. For starters, some people are confused how and why the Popup Menu "popped up" - not realizing that they probably right-clicked something. Secondly, more people are confused on how to get rid of the menu - not realizing that they can just hit or click somewhere else. One friendly way to handle this confusion: add a "Cancel" menu item to the Popup, usually positioned as a last choice. There's no code behind "Cancel"; when the user clicks it, the Popup Menu disappears!

Another confusion about Popup Menus is their relevancy: what does this menu apply to? I've been confused before - even with my own code. One solution is to add a disabled header menu item, usually at the top, that explains the purpose of the Popup. Add distinguishing characters so it doesn't look like a menu choice, such as "[Picture]". Again, there's no code behind this menu choice.

Menus can be manipulated either at design time or programmatically at run time. Here's a sample of a friendly Popup:

One more note: keep Popup Menus small. If the Popup covers the whole screen, or even half the screen, it's considered "annoying". One trick is to sub-menu items when it gets too big. Another trick is to make more than one Popup.

Update Installion Packages
When you install a program you have built, you need to install the Visual Basic runtime libraries which take up quite a bit of space. If you want to install an update to your original program, you do not need to install these libraries again. You just need to reinstall the file(s) you want to update.

To make an update installation package using the Package and Deployment Wizard, start the Wizard and begin making the installation package as usual. In the fourth step titled "Included Files," uncheck the box next to "VB6 Runtime and OLE Automation." You can also uncheck the boxes next to any other components that you do not need to update. For example, if the original version of the program uses the Common Dialog Control and the new version of the program uses the samer version of the control, then you can uncheck comdlg32.ocx.

Note that you cannot uncheck the files SETUP.EXE, SETUP1.EXE, ST6UNST.EXE, and VB6STKIT.DLL. They're small anyway.

Continue building the project. When you are done, the CAB file should be much smaller the the original one: a few hundred KB versus a couple of MB.

Const and #Const
#Const defines a compiler variable that is used by the compiler at compile time. It is used in conjunction with #If ... statements to determine what code is included in the compiled program. In the following code, the second MsgBox statement is completely removed from the code. This makes the compiled program a little smaller.
    #Const DEBUG_VERSION = True
        MsgBox "This is a debug version"
        MsgBox "This is the final version"
    #End If
Const defines a value that Visual Basic substitutes for the constant's symbol whenever it sees it. For example, this code uses a constant to make a message more readable. Often the constant is defined far from where it is used.
    Const MSG = "Hello"
    MsgBox MSG
Note that you cannot use #Const values this way. For example, this code is illegal:
    #Const MSG = "Hello"
    MsgBox MSG
Finally, note that Const values are undefined at compile time so they take their default values. For example, a Boolean constant is uninitialized at compile time so it defaults to False even if you define the constant to be True! Try to guess what the following code displays. Then try it and see if you were right.
    Private Sub Form_Load()
    #Const A = True
    Const B = True
        #If A Then
            MsgBox "A is True"
            MsgBox "A is False"
        #End If
        #If B Then
            MsgBox "B is True"
            MsgBox "B is False"
        #End If
        If B Then
            MsgBox "B is True"
            MsgBox "B is False"
        End If
    End Sub
The moral of the story, is:
  • Use #Const with #If
  • Use Const with If
  • Do not mix the two

Get Started with the Visual Data Manager (VB5)
The Visual Data Manager (VDM) is a poorly documented program with a rather strange interface so it's a bit hard to get started. You can use it to create and manage databases.

Start the VDM from the Visual Basic 5 Add-Ins menu. To create a new Access database, File\New\Microsoft Access\Version 7.0 MDB. Then enter the name of the new .mdb file to create.

To create a new table, right click on the Database window and select New Table.

To add fields to the table, click on the Add Field button. In the dialog that pops up, enter the field information: field name, data type, size (for text), AllowZeroLength, Required, etc. When you are done with that field, click Ok. The dialog stays up so you can create more fields. Click Close when you are done adding fields to the table.

When you have closed the fields dialog, you can create indexes for the table. Click on the Add Index button. Click on the fields you want to make up the index. Be sure you select them in order. Give the index a name and click the Ok button.

When you have finished describing the table, click the Build the Table button to actually create the table. You will see it appear in the Database window. Expand the TreeView representation of the table to see the list of fields. Expand a field name to see the field's properties.

To change the table's design (add or remove fields, change field definitions, etc.), right click on the table's name and select Design. To add, remove, and edit records in the table, right click on the table's name and select Open.

This should be enough to get you started. The VDM is cumbersome but useful. Most of the features are hidden inside context menus that you must right click to find. Right click on different objects to see what else you can do.

Limiting "Shareware"
First note that shareware is supposed to be shared. You rely on the user to pay you if they use your software. If you provide a restricted version of the program and then give them the full version only when they pay you, that is not shareware. If you make the program expire after a certain time period and make the user pay for a full version, that is not shareware. (In fact, this will make users hate you if they have built data files that they can no longer access).

These examples are normal software for money, with a demo version. If you sell software like this, be honest and do not call it shareware or freeware. Call the restricted version a demo version.

There are several ways you can limit a program to produce a demo version. There are some products you can buy that make this easier. I won't talk about them here, though. You can search the Web for them if you like.

The easiest way to provide a limited demo version is to make it functionally restricted. For example, make it load its data using an internal subroutine instead of loading from a file. Or disable the save features. Because the demo version and the full license version are different executables, there is no possibility of someone with a demo version making it run in full-license mode.

A traditional method is to provide a guilt screen. Every 10 or 30 minutes, the program presents a dialog saying, "You really should send in $10" or whatever. If they do, you tell them how to deactivate this screen. This is very annoying, but at least you are being fairly true to the idea of shareware. The user does not have to pay if he is willing to live with the guilt screen.

Finally, you can provide some sort of time limit or restricted protection. Realize that it is hard to protect your software completely. For example, if you time limit the software, the user can always reset his system clock if he really cares. It is easiest to just provide a separate restricted demo version.

To implement restricted features, provide a password that includes the information you need the program to have. For example, if the software has an expiration date, include it in the password. Also include some other junk to make the password more complicated and make the program verify that the password is legal.

Now encrypt the password using your favorite technique. For a serious study of cryptography, see the book Applied Cryptography.

For example, you might make the plain text version of the password be watcher01ext20end99. This will encrypt to something apparently meaningless like 1fDjh9U34jfh8Kh8747. This is the value you give to the user. During installation, you can save it to the registry if you like so the user does not need to type it in all the time.

When the program loads, it reads this password either from the user or from the registry. It decrypts it to get the original value. It verifies that the string has the format watcher--ext--end--, and it extracts the expiration date 01/20/99. It then verifies that the date has not arrived.

You can use a similar technique to store codes that indicate which functions should be allowed. Then you can make the same program work in demo or full-feature mode using different passwords.

Understanding Error Handlers
When you use On Error GoTo and an error occurs, VB enters exception mode. The line you GoTo is supposed to be the beginning of an error handler. If an error occurs within an error handler, the program stops.

What you need to do is leave the error handler and resume normal execution. Then you can use On Error to establish a new error handler for the next error. You do this with the Resume statement. See the help for details. In this case, you can use Resume LineLabel to make the program continue execution at a specific line.

Unfortunately, executing Resume from outside an error handler generates an error. Thus you cannot place the error handler in the flow of code the way you have. You need to jump out to the error handler and jump back with Resume.

Below is a subroutine that demonstrates two error handler.

    Private Sub Command1_Click()
    Dim i As Integer

        On Error GoTo Error1
        i = 1 / 0   ' Divide by zero.
        On Error GoTo Error2
        i = 1000000 ' Too big--overflow.
        MsgBox "Finishing."
        ' Do not fall through into the error handlers!
        Exit Sub

        ' Resume ends error handler mode.
        MsgBox "First error handler."
        Resume Error1Resume
        ' Resume ends error handler mode.
        MsgBox "Second error handler."
        Resume Error2Resume
    End Sub

Emptying a Collection
There are several ways you might empty a collection. This code removes items in last-in-first-out order:
    Do While col.Count > 0
        col.Remove col.Count
This code removes items in first-in-first-out order and is much faster:
    Do While col.Count > 0
        col.Remove 1
Setting the collection to Nothing is faster still:
    Dim col As Collection

        ' Allocate the collection and use it.
        Set col = New Collection
        ' Destroy the collection.
        Set col = Nothing
Thanks to Amit Mukherjee.
Use Arrays Not Collections
Arrays take less memory and are faster than collections at indexed access. If you do not need to use a collection's keyed lookup, easy extensibility, and other features, use an array instead.
Create Global Properties
Did you know you can create property procedures in a .BAS module? The rest of your program can treat the "property" just like any other variable, but the property procedures can perform error checking, one-time initialization, etc.
Protect Data Within Modules
Use private variables in BAS modules for data the module's routines must access but which should be hidden from the rest of the application.
    Private hidden_data As Integer

    Public Function GetData() As Integer
        GetData = hidden_data * 2
    End Function

When Do You Use Classes Versus Code Modules?
A deep question. The difference is mainly conceptual. If you are working with things you consider objects of a certain type, they should probably be instances of a class. If they do things, those things should be class methods (subroutines or functions). The objects' properties should be implemented with property procedures.

On the other hand, if you have a routine that applies to a more general group of "thing" than these objects, or if it does not naturally belong to any kind of object, the routine should be in a standard module.

For instance, you might have a routine that averages the numbers in an array. Your program might use lots of different kinds of arrays. You could create a class that wrapped up the functionality of an array and give it an Average method, but that would probably be over elaborate.

Personally, I use a class when either:

  1. I need to create a bunch of similar objects
  2. I want to use class methods and properties to increase encapsulation and hide functionality
Otherwise I use a standard module.
Send your Tips and Tricks to feedback@vb-helper.com.

Subscribe to the VB Helper newsletter
Copyright © 1997-2001 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
www.vb-helper.com/tips6.htm Updated