Code of the Week Logo      

Visual Basic Articles

Sign up for our free trial.


FREE Issues!

Bonus Articles

Home
First Time Visitors
Submit Your Code

FAQ
Guarantee

About...
Feedback
Contest
Web Resources
Back Issues

Order Form
      Tip of the Week Archive

This page lists all the "Tip of the Week" tips that have appeared on the Visual Basic home page.

The Visual Basic Tip of the Week is provided by The Cobb Group, publishers of Inside Visual Basic, a monthly publication for Visual Basic users. Free trial subscriptions are available. Find out how to receive the Tip of the Week in e-mail!


Febuary 2, 1998
Showing long ListBox entries as a ToolTip
By Matt Vandenbush, matt_vandenbush@whbrady.com

Sometimes the data you want to display in a list is too long for the size of ListBox you can use. When this happens, you can use some simple code to display the ListBox entries as ToolTips when the mouse passes over the ListBox.

First, start a new VB project and add a ListBox to the default form. Then declare the SendMessage API call and the constant (LB_ITEMFROMPOINT) needed for the operation:

Option Explicit

'Declare the API function call.
Private Declare Function SendMessage _
Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
' Add API constant
Private Const LB_ITEMFROMPOINT = &H1A9

Next, add some code to the form load event to fill the ListBox with data:

Private Sub Form_Load()
'
' load some items in the list box
With List1
.AddItem "Michael Clifford Amundsen"
.AddItem "Walter P.K. Smithworthy, III"
.AddItem "Alicia May Sue McPherson-Pennington"
End With
'
End Sub

Finally, in the MouseMove event of the ListBox, put the following code:

Private Sub List1_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
'
' present related tip message
'
Dim lXPoint As Long
Dim lYPoint As Long
Dim lIndex As Long
'
If Button = 0 Then ' if no button was pressed
  lXPoint = CLng(X / Screen.TwipsPerPixelX)
  lYPoint = CLng(Y / Screen.TwipsPerPixelY)
  '
  With List1
    ' get selected item from list
    lIndex = SendMessage(.hwnd, _
    LB_ITEMFROMPOINT, _
    0, _
    ByVal ((lYPoint * 65536) + lXPoint))
    ' show tip or clear last one
    If (lIndex >= 0) And (lIndex <= .ListCount) Then
      .ToolTipText = .List(lIndex)
    Else
      .ToolTipText = ""
    End If
  End With '(List1)
End If '(button=0)
'
End Sub


January 26, 1998
Creating Short Arrays Using the Variant Data Type
By Michael C. Amundsen, mike@amundsen.com

If you need to create a short list of items in an array, you can save a lot of coding by using the Variant data type instead of a dimensioned standard data type. This is especially handy when you need to create a list of short phrases to support numeric output.

For example, add a button to a standard VB form and paste the following code into the Click event of the button:

Private Sub Command1_Click()
     '
     ' create a quick array using variants
     '
     Dim aryList As Variant
     '
     aryList = Array("No Access", "Read-Only", "Update", "Delete")
     '
     MsgBox aryList(2)
     '
End Sub


January 19, 1998
Using GetRows to Quickly Save Data Fields to Memory Variables
By Michael C. Amundsen,
mike@amundsen.com

If you need to copy information from database fields into memory variables, you can do it quickly using the GetRows method of the Recordset object. The GetRows method copies one or more rows of data directly into a Variant data type and stores the information as a two-dimensional array in the formvarData(Field,Column).

To test the GetRow method, add a button to a VB form and paste the following code into the Click event of the button. Be sure to fix the reference to location of the BIBLIO.MDB database in the OpenDatabase method. Also be sure to set up a reference to the Microsoft DAO 3.5 Object Library.

Private Sub cmdGetDataRow_Click()
     '
     ' show getrow method
     '

     Dim ws As Workspace
     Dim db As Database
     Dim rs As Recordset
     '

     Dim varDataRows As Variant
     Dim intRows As Integer
     Dim intColumns As Integer
     '

     Dim intLoopRow As Integer
     Dim intLoopCol As Integer
     Dim strMsg As String
     '

     Set ws = DBEngine.CreateWorkspace(App.EXEName, "admin", "")
     Set db = ws.OpenDatabase("e:\devstudio\vb\biblio.mdb")
     Set rs = db.OpenRecordset("SELECT * FROM Authors")
     '

     intRows = InputBox("How Many Rows?", "GetRows Example", 0)
     intColumns = rs.Fields.Count
     varDataRows = rs.GetRows(intRows)
     '

     For intLoopRow = 0 To intRows - 1
          strMsg = ""
          For intLoopCol = 0 To intColumns - 1
               strMsg = strMsg & varDataRows(intLoopCol, intLoopRow) & vbCrLf
          Next
          MsgBox strMsg
     Next
     '
     rs.Close
     db.Close
     ws.Close
End Sub



January 12, 1998
Getting sensible Win32 API call errors
By Duncan Jones, Duncan_Jones@compuserve.com

Most of the Win32 API calls return extended error information when they fail. To get this information in a sensible format, you can use the GetLastError and FormatMessage APIs.

Add the following declarations and function to a BAS module in a VB project:

Option Explicit

Public Declare Function GetLastError _
     Lib "kernel32" () As Long
Public Declare Function FormatMessage _
     Lib "kernel32" Alias "FormatMessageA" _
     (ByVal dwFlags As Long, _
     lpSource As Any, _
     ByVal dwMessageId As Long, _
     ByVal dwLanguageId As Long, _
     ByVal lpBuffer As String, _
     ByVal nSize As Long, _
     Arguments As Long) As Long

Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000

Public Function LastSystemError() As String
     '
     ' better system error
     '

     Dim sError As String * 500
     Dim lErrNum As Long
     Dim lErrMsg As Long
     '

     lErrNum = GetLastError
     lErrMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, _
          ByVal 0&, lErrNum, 0, sError, Len(sError), 0)
     LastSystemError = Trim(sError)
     '

End Function

Now place a command button on a standard VB form and call the LastSystemError function:

Private Sub Command1_Click()
     '
     MsgBox LastSystemError
     '

End Sub

If there was no error registered, you'll see a message saying "The operation completed Successfully."

When using this function, keep these points in mind:

1. Many API calls reset the value of GetLastError when successful, so the function must be called immediately after the API call that failed.

2. The last error value is kept on a per-thread basis, therefore the function must be called from the same thread as the API call that failed.


January 5, 1998
Simple input validation
by Juan Lozano, jlozano@truevision.net

Here's a way to achieve validation in text boxes and other controls that support the KeyPress event. It's simple, but functional.

First, add this function to your project:

Function ValiText(KeyIn As Integer, _
ValidateString As String, _
Editable As Boolean) As Integer
Dim ValidateList As String
Dim KeyOut As Integer
'
If Editable = True Then
ValidateList = UCase(ValidateString) & Chr(8)
Else
ValidateList = UCase(ValidateString)
End If
'
If InStr(1, ValidateList, UCase(Chr(KeyIn)), 1) > 0 Then
KeyOut = KeyIn
Else
KeyOut = 0
Beep
End If
'
ValiText = KeyOut
'
End Function

Then, for each control whose input you wish to validate, just put something like this in the KeyPress event of the control:

KeyAscii=ValiText(Keyascii, "0123456789/-",True)

Doing so will filter out any undesired keys that go to the control, accepting only the keys defined by the second parameter. In this case, that parameter ("0123456789/-") defines characters that are valid for a date.

The function's third parameter controls whether the [Backspace] key can be used.

Note that this implementation of the function ignores the case of the incoming keys, so if your second parameter were "abcdefg", the function would also allow "ABCDEFG" to be entered.


December 29, 1997
Simplying the addition of items to ComboBoxes
by Brent Langdon, blangdon@sequeltech.com

I often need to add items to a ComboBox and store an index or ID value in the ItemData property. I've found that the code needed to add items to the ComboBox and to check the ItemData property of the currently selected item looks clumsy. So, I've written two simple helper routines to clean the code up a bit. Here they are:

'----------------------------
' AddComboItem
'----------------------------
Public Sub AddComboItem( _
     cboAdd As ComboBox, _
     ByVal sText As String, _
     ByVal lData As Long)

     cboAdd.AddItem sText
     cboAdd.ItemData(cboAdd.NewIndex) = lData

End Sub

'----------------------------
' CurrComboData
'----------------------------
Public Function CurrComboData( _
     cbo As ComboBox) As Long

     If cbo.ListIndex <> -1 Then
          CurrComboData = cbo.ItemData(cbo.ListIndex)
     Else
          CurrComboData = -1
     End If

End Function

Now, instead of writing

cboTest.AddItem "Hello"
cboTest.ItemData(cboTest.NewIndex) = 5

you can just write

AddComboItem cboTest, "Hello",5

Instead of writing

ID = cboTest.ItemData(cboTest.ListIndex)

you can write

ID = CurrComboData( cboTest )

As an added bonus, CurrComboData protects you from the runtime error generated if ListIndex is -1. Just be sure to check for a return of -1 from CurrComboData.


December 22, 1997
Specifying maximum lengths in a ComboBox
by Roberto Giacometti Machado, rmachado@opus.com.br

The ComboBox control doesn't have a MaxLength property like a TextBox does. You can add some code to emulate this property, however. Just add the following code to the KeyPress event of your ComboBox:

Private Sub Combo1_KeyPress(KeyAscii As Integer)
     'If the user is trying to type the eleventh key and...
     ' ...this key is not the Backspace Key, cancel the event!
     Const MAXLENGTH = 10
     If Len(Combo1.Text) >= MAXLENGTH And KeyAscii <> vbKeyBack Then KeyAscii = 0
     '
End Sub

You can change the MaxLength value to any number you want. As you can see, the code allows the user to use the [Backspace] key; you could enable other keys by simply adding their KeyAscii values the way we did with [Backspace].


December 15, 1997
Clearing all fields and combo boxes on a form
By John Baumbach, jbaumbach @kw.edu

Sometimes you want to clear all the fields and combo boxes on a data-entry form. If your form contains many controls, this could become tedious and error prone. The following subroutine clears the contents of such fields on your form automatically:

Public Sub ClearAllControls(frmForm As Form) Dim ctlControl As Object

     ' Initialize all controls that can be initialized
     ' Any control with a text property or a list-index property
     On Error Resume Next
     For Each ctlControl In frmForm.Controls
          ctlControl.Text = ""
          ctlControl.ListIndex = -1
          DoEvents
     Next ctlControl

End Sub

Just call this procedure from your code like this:

Call ClearAllControls(Me)


December 8, 1997
Selecting all text when a TextBox gets focus
By Christopher Buteau, cbuteau@fastech.com

When you present the user with default text in a TextBox, you'll often want to select that text when the TextBox gets focus. That way, the user can easily type over your default text.

The function below will do the trick. The first click on the TextBox will select all the text; the second click will place the cursor.

Public Sub TextSelected()
Dim i As Integer
Dim oMyTextBox As Object

Set oMyTextBox = Screen.ActiveControl
     If TypeName(oMyTextBox) = "TextBox" Then
          i = Len(oMyTextBox.Text)
          oMyTextBox.SelStart = 0
          oMyTextBox.SelLength = i
     End If
End Sub

Just add the function to your project and call it from the TextBox's GotFocus event.

Private Sub Text1_GotFocus()
     TextSelected
End Sub

Editor's Note: A similar tip was submitted by Alan Brown, algernon@btinternet.com.


December 1, 1997
Preventing Add-Ins from loading at launch
by Deborah Kurata, deborahk@insteptech.com

When you launch Visual Basic 4 or 5, any active Add-Ins also launch. If there's an error in one of the Add-Ins, however, you could encounter a global protection fault.

To prevent this from happening, you can turn off Add-Ins before launching VB. To do so, launch Notepad or WordPad and open the file VBAddin.INI in your Windows directory. You'll see a series of entries like this:

AppWizard.Wizard=1

Just change the "1" to a "0" in each entry. Then save the file and launch VB. The program will launch without any Add-Ins.

Of course, to add and remove Add-Ins while you're in Visual Basic, just choose Add-In Manager from the Add-Ins menu.


November 24, 1997
Quickly switching an object's Enabled property
by Kevin Brown, Kevin@taskware.vaxxine.com, www.basic.ca

You can easily switch an object's Enabled property with a single line of code:

optSwitch.enabled = abs(optSwitch.enabled) - 1

Here's how the technique works: When Enabled is True, its numeric value is -1. The absolute value of -1 is 1, so subtracting 1 from 1 would yield 0, which is False. When Enabled is False, its numeric value is 0; 0 - 1 would then yield -1, or True.

This technique is an enhancement of the common usage

fraOption.enabled = optSwitch.enabled

to have an object follow the value of any other object's Enabled property.

Editor's Note: This technique depends on VB's definition of True and False. To make this technique less dependent on that definition, you can use the following code:

OptSwitch.enabled = NOT OptSwitch.enabled

This code works for any Boolean data type.


November 17, 1997
Dealing with Null strings in Access database fields
by Pradeep Arora, PradeepArora@trilogyworld.com

By default Access string fields contain NULL values unless a string value (including a blank string like "") has been assigned. When you read these fields using recordsets into VB string variables, you get a runtime type-mismatch error. The best way to deal with this problem is to use the built-in & operator to concatenate a blank string to each field as you read it. For example,

Dim DB As Database
Dim RS As Recordset
Dim sYear As String

Set DB = OpenDatabase("Biblio.mdb")
Set RS = DB.OpenRecordset("Authors")
sYear = "" & RS![Year Born]

Editor's note: A similar tip was also sent in by Fran Arreciado, franac@cinsa.es


November 10, 1997
Customizing a text box's pop-up menu
by CMD Software, support@cmdsoftware.softnet.co.uk

In Windows 95, right-clicking any text box brings up a context menu with basic edit commands on it. If you want to change this menu, put the following code in the MouseDown event of the text box.

If Button = vbRightButton Then
     Text1.Enabled = False
     Text1.Enabled = True
     Text1.SetFocus
     PopUpMenu Menu1
End If

where Text1 is the text box and Menu1 is the pop-up menu.

Disabling and re-enabling the control causes Windows to lose the MouseDown message, SetFocus tidies things up a bit, and PopUpMenu shows the menu.
Left clicks will work as always, allowing the user to edit the text in the text box.


November 3, 1997
Retrieving the network logon name
by Barron Anderson, Micron Electronics Inc.

You can easily retrieve a user's network logon name by using the following API call:

Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

To retrieve a "clean" version of the name, use this function:

Public Function NTDomainUserName() As String
Dim strBuffer As String * 255
Dim lngBufferLength As Long
Dim lngRet As Long
Dim strTemp As String

    lngBufferLength = 255
    lngRet = GetUserName(strBuffer, lngBufferLength)
    strTemp = UCase(Trim$(strBuffer))
    NTDomainUserName = Left$(strTemp, Len(strTemp) - 1)

End Function


October 27, 1997
Preventing multiple instances of VB apps
by Saptadeep Dutta

You can easily prevent users from running multiple instances of your programs by taking advantage of the PrevInstance property of the App object.

To do so, enter the following code in your application's opening form:

If App.PrevInstance Then
    MsgBox ("Cannot load program again."), vbExclamation, "The requested " _
    & "application is already open"
    Unload me
End If

This technique will also prevent multiple users from accessing single-user applications.


October 20, 1997
Case-conversion on the fly
by Chris Warnke, Dell Computer Corp.

If you want to convert text to uppercase as it's entered in a text box, just create an Upper function and call it from the text box's keypress event, as shown here:

     Private Sub Text1_KeyPress(KeyAscii As Integer)
        KeyAscii = Upper(KeyAscii)
    End Sub

    Function Upper(KeyAscii As Integer)
        If KeyAscii > 96 And KeyAscii < 123 Then
            KeyAscii = KeyAscii - 32
        End If
        Upper = KeyAscii
    End Function

This technique eliminates the need to "UCase" entered data. It also makes "hotseek" data searches much easier.


October 13, 1997
Trapping dropdown list errors
by Raul M. Rodriguez,

In VB, the Text property of a Combo box whose Style property is set to '2 - Dropdown List' is read-only. This means that a statement like MyCombo.Text = "The Third Item" will return an error if "The Third Item" is not part of the list. Wouldn't it be nice if VB just set the Combo box's ListIndex property to -1 (blanking it out) instead of bombing out? Well, here's some code that will do just that:

Function SetComboText(MyCombo as ComboBox, MyItem as String) as Integer
    Dim I as Integer

    For I = 0 to MyCombo.ListCount - 1
        If MyCombo.List(I) = MyItem Then
            SetComboText = I
            Exit Function
        End If
    Next I

    ' If the program reaches this point, the string is not in the
    ' list.
    SetComboText = - 1
End Function

Use the function like this:
AnyCombo.ListIndex = SetComboText(AnyCombo, "Any String") If "Any String" is in the list, then the combo box's ListIndex will be set to the correct index; if not, it will be blanked out. The great thing about this code is that if you want to do something else other than blanking out the combo box, all you have to do is replace the line SetComboText = - 1 with whatever you wish.


October 06, 1997
Speed up string buffers
by John C. Hancock

Sometimes you need to write a program that builds up a large amount of data in a string variable. You'd normally use a statement such as

strBuffer = strBuffer & strNewData

during every loop. The problem with this approach is that the bigger your string buffer becomes, the slower your program runs.

A neat and very simple way around this problem is to use another buffer. Just fill the temporary buffer with data, and when it's big enough, append it to the main buffer. Then, clear the temporary buffer and continue. The code will look like this:

Public Sub NewBuildBuffer()
     Dim strBuffer As String, strTemp As String
     Dim l As Long, dStart As Date

     'Set start time
     dStart = Now

     'Build the buffer
     For l = 1 To 10000
          strTemp = strTemp & "New Line" & vbCrLf
          'Append to the main buffer every 100 times
          If l Mod 100 = 0 Then
               strBuffer = strBuffer & strTemp
               strTemp = ""
          End If
     Next
     'Append the last temp buffer
     strBuffer = strBuffer & strTemp

     'Report total time
     MsgBox "Seconds taken = " & DateDiff("s", dStart, Now)
End Sub

For programs that use very large string buffers, you'll see a huge improvement.


September 29, 1997
Finding a property quickly
by Domenic Rico

Have you ever tried looking for a property in the properties window by typing in the first letter of the property's name? The properties window doesn't work this way.

Here's a tip that will help. In the properties window, hold down [Ctrl][Shift] while pressing the letter you're looking for. The properties window will then scroll to the next property (if any) that begins with the letter.


September 22, 1997
Centering a form
by Barron Anderson, Micron Electronics, Inc.

To center a form on the screen in VB3 or VB4, you can write a CenterForm subroutine. Then, call CenterForm in the form's Load event. The code is as follows:

Public Sub CenterForm(frmTarget As Form)
     frmTarget.Move (Screen.Width - frmTarget.Width) / 2, _
          (Screen.Height - frmTarget.Height) / 2
End Sub

Private Sub Form_Load()
     CenterForm Me
End Sub

Editor's Note:
In VB5, you can center a form on the screen by setting the StartUpPosition property of the form to CenterScreen or CenterOwner.


September 15,1997
Prevent partially painted windows
by Deborah Kurata; InStep Technologies, Inc.

Sometimes when you display a form, only some of the controls appear. After a pause, the remaining controls appear. Such partial painting doesn't look professional. (Fortunately, this problem is much less apparent in VB 5.0 because of dramatic improvements in screen painting.)

To avoid partially painted windows when showing a non-modal form, use the following code:

frmPerson.Show vbModeless
frmPerson.Refresh

The Refresh method will ensure that the form repainting is complete before executing any other code in the routine.


September 8,1997
Sharing resource files between VB and C projects
by Victor Brito; vbrito@eldcom.eld2.com; Electronique D2

Suppose you want to use a resource file (RES) in your Visual Basic project, but some of the file's resource indexes are greater than 0x8000. The VB function LoadResString(index) receives an integer argument Index in the range -32,768 to 32,767, so you can't pass values that are larger than 0x8000. You can solve this problem by passing the corresponding negative index value, as follows (with 0 <=X < 0x8000):

RESVisual Basic
0xFFFF - X-X - 1
0x8000+XX-0x8000
 
For example, suppose you have the following RC file:

     STRINGTABLE DISCARDABLE
     BEGIN
       0xFFFF-0x0000         "resource string 1 with VB index -0 - 1 = -1"
       0x8000+1              "resource string 2 with VB index 1 - 32,768= -32,767"
     END

To load string 1, you'll use LoadResString(-1). Similarly, to load string 2 you'll use LoadResString(-32767).


September 1, 1997
The CDbl function versus Val
by Lee Gillie; Lee@odp.com; Online Data Processing, Inc.

The Val() function is familiar, and it's useful for converting text box numeric values to numbers. But if you use formatters to display large numbers (with commas, for instance), there's a better function for your purpose. The following example illustrate the use of Val versus CDbl:

     print Val("12345")
        12345
     print Val("12,345")
        12
     print CDbl("12,345")
        12345
     print CDbl("12345")
        12345

Why are these functions different? The Visual Basic Help file offers several hints. You should use the CDbl function instead of Val to provide internationally aware conversions from any other data type to a Double. For example, CDbl will recognize different decimal separators and thousands separators properly depending on your system's locale.
Also, if you want your display and input routines to be automatically reversible, you may want to consider using named formatters for FORMAT$() rather than display pictures. Doing so helps guarantee a reversible process, given the LOCALE setting of the user's machine.


August 25, 1997
Displaying and processing a message box
by Greg Osborne; greg.osborne@worldnet.att.net; Osborne Software

The following code sample demonstrates an easy way to display and process a message box (MsgBox) in any version of Visual Basic:

     Select Case MsgBox("Would you like to save the file somefile.txt?", _
     vbApplicationModal + vbQuestion + YesNoCancel, App.Title)
       Case vbYes
          'Save then file
       Case vbNo
          'Do something for No
       Case vbCancel
          'Do something else for Cancel
     End Select

This method works well, unless you need to save the answer from your Select Case for later use. If you do, you'll need to use the more standard form of prompting for the answer in a variable.


August 18, 1997
Passing strings to a DLL
by Paul Malachowski; paul@softwaregw.com; Software GW

I recently came across a serious inefficiency in the way Visual Basic sends strings to a DLL. The problem occurs when you want to get back a large string field (32 KB) from a DLL written in C/C++. VB interacts somehow with this string, causing significant overhead. In order to call a DLL and get back a string-type data field, you must pass a string and initialize it for as many bytes as you expect to be returned. If you pass this function a small string, it will run quickly. But if you pass it a large string (32 KB), the time will be significantly slower. You'll see this slower performance even when no data is being returned, meaning that the extra time results from some sort of VB overhead. As a result, if speed is an issue when you're calling a DLL and passing a string variable, you should pass a string that's only as large as you need.
You can find a sample project that demonstrates this problem in the file Speed.zip at ftp.cobb.com/ivb/tipcode. The project simply loops for a predetermined number of times and issues the standard windows API call GetPrivateProfileString, which gets data from an INI file.


August 11, 1997
Creating a formless application
by Zafar Faquih; zafar.faquih@bchydro.bc.ca; Westech Information Systems

To create a VB program that has only console input and output -- that is, no dialog boxes or forms -- you can use the Main procedure. Begin by creating a new project. Open a code window, then choose Insert | Procedure…. In the Insert Procedure dialog box, Select the Sub and Public options and enter Main in the Name box. Click OK to create a new Main subroutine in the General object. All your code will go in this routine; if you have any useful BAS modules, you can add those to the project as well.
VB needs to know what code to execute when your application is called. Since you're not using a form, you need to tell VB to start execution with Sub Main. To do so, choose Tools | Options…. Click the Project tab and select Sub Main from the Startup Form list. To remove the project's default form, right-click on it in the Project window and choose Remove File from the speed menu.
Testing a formless application can be a headache, so plan ahead: Use a log file to get debug messages from your application. You'll want to read about the Print # statement in VB's Help file, along with Open and Close.
Note that you can use this method to create a VB application that will run as a service on NT. (Services can't have any forms or dialog boxes.)


August 4, 1997
Making a text box read-only
by Daniel Sobstel; danny@omniquad.com

Here's a quick and easy way to make a text box read-only. Simply enter the line

     keyascii = 0

in the textbox_keypress event.


July 25, 1997
Putting months in a combo box
by James Westgate; JamesW@vircom.co.za; Vircom

Here's a cool technique for loading a combo box with the months of a year:

     'Load Months Combo
     For i = 1 To 12
       cmbMonth.AddItem Format("28/" & i & "/1997", "mmmm")
     Next

To see which month the user clicked, you can use the following code:

     Private Sub cmbMonth_Click ()
     Dim myRs as recordset
       .
       .
       .
       myRs!Month = cmbMonth.listindex + 1
     Next


July 18, 1997
Checking the value of a control
by Jeff Brown; Jeff.Brown@piog.com; Pioneering Management Corporation

I've recently taken over a project from someone else, and I've been left with code that has few naming conventions and a lot of bugs. I often find myself stepping through code wanting to check the value of a field. Unfortunately, I don't know the field's name—it could be Name, UserName, NameUser, txtName, and so on. It's a real pain to stop the program, click on the control in question, press [F4], get the control name, start the program again, and return to the point in the code where I was before. Here's a handy trick to get the control name right away.
At runtime, set the focus to the control in question. Then, click the Break button on the VB toolbar, type

   ?Screen.ActiveControl.Name

in the debug window, and press [Enter]. Voila! VB displays the control name in the debug window—and you didn't have to stop the program.


July 12, 1997
Command me, oh great one
by Chuck Kraatz; ETC Software Solutions; Chuck_Kraatz@msn.com

Suppose you want to use Visual Basic to create an EXE that takes an input value in a format like test.exe 2. Depending on the input value, you'll perform certain tasks. In this situation, you can make use of the Command function, which returns the argument portion of the command line you use to launch VB or an EXE you develop in VB.

It's easy to send command-line information to an application. For instance, to send information to an application called HappyApp, you could use the line

HappyApp /CMD 1972

Now, within the application—probably in the Sub Main—you can use the Command function to capture that command-line information.

To see this technique work, place a text box on a form. In the Form_Load event, place the following line:

Text1.Text = Command

While still in VB, place some code on the command line. To do this in VB 3.0, choose Options | Project; in VB 4.0, choose Tools | Options…, then click the Advanced tab; in VB 5.0, choose Project | Project Properties, then click the Make tab. Next, type This is my argument in the Command Line Arguments section and click OK. Run the application, and your command-line text will appear in the text box.

Note that if you're working with 32-bit VB, you may want to create an ActiveX EXE or ActiveX DLL (formerly OLE Automation servers). By doing so, you simply deal with property settings.


July 7, 1997
In-process servers versus out-of-process servers

You can compile an OLE server as an OLE Dynamic Link Library (DLL) or an executable (EXE) file. Compiling as a DLL creates an in-process server, while compiling as an EXE file creates an out-of-process server.

In-process servers run in the client's address space; for this reason, in-process servers are faster than out-of-process servers. On the other hand, because out-of-process servers run in their own address space, they have capabilities that are unavailable with in-process servers. For instance, they can run asynchronously. (An asynchronous process can display modeless forms and run in the background.) In deciding whether to use an in-process or an out-of-process server, you'll need to consider the tradeoff between speed and flexibility.


June 30, 1997
Validating with the Name property (VB 4.0)
by Chuck Kraatz; ETC Software Solutions; Chuck_Kraatz@msn.com

The Name property can be very useful when you're validating data. For instance, suppose you have a data input screen with three text fields, and you want to be sure the user has entered a valid date in each control. The trick lies in placing the word Date in the name of every text control that will contain date-type data—for this example, create such a form and name the text fields txtDateOfBirth, txtHireDate, and txtDateLastReview.

Add an Update command button to the form, and place the following code in its Click event:

If Not ValidDates() Then
 MsgBox "Some of the dates entered are invalid"
 Screen.MousePointer = vbDefault
 Exit Sub
End If

Notice that since this block leaves the sub early via the Exit Sub statement, you must reset the mouse pointer to its default shape.

Next, enter the following ValidDate function, which uses VB's built-in Controls array:

Private Function ValidDates() As Boolean
Dim ctl As Control
Dim bInValid As Boolean

For Each ctl In Me.Controls
 Debug.Print ctl.Name
 If TypeOf ctl Is TextBox Then
  If InStr(1, ctl.Name, "Date") > 1 And _
   ctl.Text <> "" Then
   bInValid = Not IsDate(ctl.Text)
   If bInValid Then
    ValidDates = False
    Exit Function
   End If
  End If
 End If
Next
ValidDates = True
End Function

Run the project and enter the values 2/7/64, 7/8/93, and To be scheduled in the three fields. When you click Update, a message box will inform you that a date is invalid. Click OK, then enter 10/31/96 in the Date Of Last Review text box—this time, VB won't object when you click Update


June 19, 1997
Quick block indents

To quickly indent an entire block of Visual Basic code, select the text and press the [Tab] key. You can just as easily move a code block out one tab stop by selecting the text and pressing [Shift][Tab].


June 12, 1997
Getting a field name (VB 3.0 and 4.0)
by Chuck Kraatz; ETC Software Solutions; Chuck_Kraatz@msn.com

Suppose you want to use a generic routine to get the name of a field to assign to a variable, while using OLE to write the records of an Access database to an Excel worksheet. Once you have an open recordset—let's call it rsMine—the lines

sString = rsMine.Fields(0).Name
sString = rsMine.Fields(1).Name

retrieve the first two fields names. You'll normally loop through the recordset and match the grid columns with the fields in the database. But be cautious—often the field name isn't a good title for the grid. The end user also may not understand a developer's naming conventions.

For example, place a Grid control on a form and select the Microsoft DAO 2.5/3.0 Compatibility Library option in the References dialog box. Then enter the following code, which is written in VB 4.0 syntax and uses the BIBLIO.MDB database. The code finds the names of the database fields, then enters those names into the grid columns. Notice that you use a Forward Only snapshot type recordset, which is very fast and very small. Since you'll read and move on, you don't need to scroll through the recordset.

Option Explicit

'Set form-level DB variable for this example
Private dbCurrent As Database

Private Sub Form_Load()
Dim rs As Recordset
Set dbCurrent = OpenDatabase("C:\Program Files\Microsoft Visual Basic\biblio.mdb")
Set rs = dbCurrent.OpenRecordset("Publishers", dbOpenSnapshot, dbForwardOnly)
If rs.RecordCount <> 0 Then
  ColumnNames rs, Grid1
End If
End Sub

Private Sub ColumnNames(rs As Recordset, grd As Grid)
Dim fld As Field
Dim iCol As Integer
iCol = 0
grd.Cols = rs.Fields.Count
grd.Row = 0
For Each fld In rs.Fields
  grd.Col = iCol
  grd.Text = fld.Name
  iCol = iCol + 1
Next
End Sub


June 5, 1997
Slow to load?
by Bill Shadish; Fundamental Objects, Inc.

If you find that your application loads slowly, you may be loading more than you think at start-up. Try the following steps to correct the problem: Load your application in Visual Basic's design mode and press [F8] to start it. Keep pressing [F8] to run your code one line at a time, and observe what's really going on as your code executes. For example, suppose your Sub Main() code looks like this:

frmSplash.show vbModal
frmMain.show

You may feel confident that you won't execute (or Load) the frmMain code before the user sees the splash screen. But if your splash screen reads application parameters, and those routines set properties on frmMain--perhaps you save the user's frmMain screen color choices between runs, or save the application's WindowState--then frmMain will silently (and slowly) load in the background while frmSplash tries to display itself.

You may also experience slow loading if you call the same routine several times from different places during your start-up process. For example, in heavily maintained code, it isn't impossible for the application to load the application's parameters in a splash screen and again later for use within frmMain. Removing the extraneous, repeated call saves that much time in loading. (There are a number of places where you may find duplicate code, especially if you copy lots of forms and modules from one application to start another.)


May 26, 1997
Rearranging your PME order (VB 5.0)
By default, Visual Basic 5.0's Object Browser (View | Object Browser) displays properties, methods, and events in a single, alphabetical list. If you'd prefer to see these members grouped by type, then right-click in the window and choose Group Members from the context menu. VB will group all the elements in the window's Classes and Members lists.
May 19, 1997
Auto-searching by entering text in a combo box
by Chuck Kraatz

An auto-searching combo box finds a possible selection as the user enters information directly into the text portion of the combo box. For this example, you can use the Authors table from Visual Basic's BIBLIO.MDB database. Place the following code in a standard module (BAS file):

Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long

Public Const CB_FINDSTRING = &H14C

(If you're using 16-bit VB, make the appropriate adjustments to the declare statement.)

You'll need a static variable-one that remembers its value from each previous call to that subroutine or function-to keep track of how many characters you've entered in the combo box at any given time.

Enter the following code in the combo box's Change event:

Private Sub Combo1_Change()
Dim iStart As Integer
Dim sString As String
Static iLeftOff As Integer
 
iStart = 1
iStart = Combo1.SelStart
 
If iLeftOff <> 0 Then
  Combo1.SelStart = iLeftOff
  iStart = iLeftOff
End If

sString = CStr(Left(Combo1.Text, iStart))
Combo1.ListIndex = SendMessage(Combo1.hwnd, _
 CB_FINDSTRING, -1, ByVal CStr(Left( _
 Combo1.Text, iStart)))

If Combo1.ListIndex = -1 Then
 iLeftOff = Len(sString)
 Combo1.Text = sString
End If

Combo1.SelStart = iStart
iLeftOff = 0
End Sub

The static variable iLeftOff helps determine how many characters you need to use in the sString variable that you then pass to the API call.

Run the application and notice how the cursor position stays at the proper position as you enter characters. The combo box displays a name if VB finds a match; otherwise, only the entered text appears.


May 13, 1997
Closing a DOS prompt window
by Chuck Kraatz

After you run a DOS application in Windows 95, the MS-DOS Prompt window doesn't close. To prevent this behavior, you can use the API to find the Window handle for the DOS prompt window, wait for the program to finish running, then zap the DOS prompt window into oblivion.
This technique doesn't require any forms. It's just a simple VB 4.0 DLL with two properties: the EXE name of the DOS program and the text that will appear as the caption of the DOS prompt window displaying this application. The core of this app lies in three API calls. Place the following code in a standard module:

Declare Function FindWindow& Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String)

Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Const WM_CLOSE = &H10

The rest of the code goes in the following class module, named Cclose:

     Private m_sEXEName As String
     Private m_sDosCaption As String

     Public Sub RunDosApp()
     Dim vReturnValue As Variant
     Dim lRet As Long
     Dim i As Integer

     vReturnValue = Shell(m_sEXEName, 1) ' Run EXE
     AppActivate vReturnValue ' Activate EXE Window

     Do
      Sleep (10000)
      lRet = FindWindow(vbNullString, m_sDosCaption)
      If (lRet <> 0) Then
          vReturnValue = SendMessage(lRet, WM_CLOSE, &O0, &O0)
          Exit Do
      End If
     Loop
     End Sub


May 6, 1997
Determining whether a file exists
Visual Basic doesn't provide any built-in means for telling whether a particular file exists. However, you can use the DIR or DIR$ function to check a file's existence. Simply pass the filename to the DIR function and check the function's return value-if the function returns nothing (""), then there's no such file.
To try this technique, create a VB project, place a button on Form1, and enter the following code in the button's Click event:

Private Sub Command1_Click()
FileInQuestion = Dir("C:\AUTOEXEC.BAT")
If FileInQuestion = "" Then
  MsgBox "No such file!"
Else
  MsgBox "File exists!"
End If
End Sub
When you run the form and click the button, you'll see the success message box. To complete the test, edit the code so it searches for a file you know doesn't exist on your C: drive.
April 22, 1997
VB 5.0 IsMissing() caution
by Bill Shandish
A great enhancement of VB 4.0 was the ability to have optional parameters within your procedures, like so:
Sub CenterButtons(frm As Form, Control1 As Variant, Optional Control2 As Variant)
VB 4.0's isMissing( ) function determines whether you've omitted an optional parameter. You can decide on the fly what to do, given the number of parameters supplied by the caller of your procedure. A drawback of the VB 4.0 optional parameters is that you have to declare them as Variants-you must interpret the passed object within your code to decide if it's the type you expect to get.
VB 5.0 removes this restriction, and you can now happily pass as optional parameters everything from Bytes to Controls. However, the isMissing( ) function has changed. Suppose you omit passing a Control2 using the following code:
Sub CenterButtons(frm As Form, Control1 As Control, Optional Control2 As Control)
' VB5 code to center buttons across the bottom of the screen.
'
If Not frm.Visible Then Exit Sub
'
If IsMissing(Control2) Then
   ' you have only 1 button
...
Control2 will equal Nothing, and the isMissing( ) call will return False rather than True for the omitted control. As a result, the code within the If IsMissing block will be bypassed by mistake. The moral: Test your isMissing( ) calls to be sure they're behaving as expected.
April 10, 1997
Is VB Running? A Simple Function Will Tell You
by David Mendlen
You can write a one-line function that will tell you if Visual Basic 5.0 is in run mode or design mode. The InRunMode() function is as follows:
Function InRunMode(VBinst As VBIDE.VBE) As Boolean
InRunMode = (VBinst.CommandBars("Run").Controls("End").Enabled = True)
End Function

March 31, 1997
Getting a Reference to a Visual Basic 5.0 UserControl
by David Mendlen
Visual Basic 5.0 allows you to use UserControls to create ActiveX controls in your projects. The following code snippet does two things: It gets a reference to the form in which a UserControl is placed, and it gets a reference to that control on the form.
Dim PControl As Object
Dim MyControl As Control
Dim AControl As Object
'Get my UserControl
For Each AControl In ParentControls
  If AControl.Name = Ambient.DisplayName Then
    Set MyControl = AControl
    Exit For
  End If
Next
'Get the Form UserControl is on
Set PControl = ParentControls.Item(1).Parent
While Not (TypeOf PControl Is Form)   Set PControl = PControl.Parent
Wend

17 March 1997
Visible Cues from a Minimized Form.
by Chuck Kraatz
Suppose you want a form to perform a task while minimized, then notify the user without a message box and while remaining minimized. You can send a message via a changing icon on the minimized form in the taskbar.

Create a form containing a timer and an image list. Set the timer's Interval property to 2000, then use the ImageList control's Custom property to add three images. Finally, add this code to the Timer event:

Private Sub Timer1_Timer()
Static ilmage As Integer
ilmage = ilmage + 1
If ilmage > 3 Then ilmage = 1
Me.Icon = ImageList1.ListImages(ilmage).Picture
EndSub

7 March 1997
Cleaning Out Invalid Registry Entries.
by David Mendlen
Tired of all of those obsolete OCXs in your Components dialog box? Run RegClean.EXE. This utility is available for download, free of charge, from the Microsoft Knowledge Base at http://www.microsoft.com/kb/articles/q147/7/69.htm. RegClean runs through your CLSID and GUIDS and checks for valid entries. It also provides a number of Registry Scan options and lets you choose whether the utility should make corrections automatically or simply report its findings.
28 February 1997
Passing a UDT Between Objects.
by Chuck Kraatz
You can use a user-defined type within an object if it passes to private routines or functions — just include a property in the class/object that mirrors every member of the UDT. Suppose you define the UDT:
Type TestUDT
Score As Integer
Player As String
End Type

and a Cgame class with properties for Score and Player. You'd pass each UDT member with code like this:

Private Sub SendUDT()
Dim xUDT As TestUDT
xUDT.Player = "Michael Jordan"
xUDT.Score = 45
PassUDT xUDT
End Sub

Public Sub PassUDT(Z As TestUDT)
Dim x as New Cgame
Cgame.Score = Z.Score
Cgame.Player = Z.Player
End Sub

21 February 1997
Run Time- and Design Time-Only Properties in Visual Basic 5.0.
To distinguish between run time-only and design time-only properties, check for the value of the Ambient.Usermode property within the Property Get and Property Let/Set procedures. Usermode is True at run time and False at design time. Also, in the Procedure Attributes window (Tools | Procedure Attributes...), select the Don't Show In Property Browser option to prevent the developer from trying to set a run time-only property. To create read-only run time properties, bypass the Property Let/Set procedure entirely in the ReadProperties event of the UserControl, and assign the retrieved value to it directly.
14 February 1997
Highlighting Text Upon Entering a Field.
You can highlight the contents of a text box when you tab to the control by calling the following subroutine from the control's Got_Focus event:
Public Sub SelAllText() Screen,ActiveControl.SelStart = 0 Screen.ActiveControl.SelLength = Len(Screen,ActiveControl.Text) EndSub

You can also use a second method, which may give you more flexibility if you're going to use it with objects other than text boxes:

Public Sub SelAllText(ctl as Control) ctl.SelStart = 0 ctl.SelLength = Len(ctl.Text) EndSub

7 February 1997
Drag-and-drop in Visual Basic 5.0.
Drag-and-drop — It's not just for Word anymore! Visual Basic 5.0 offers control properties and events that let you drag and drop just as you can in Word and other Microsoft Office applications. To test this functionality, place two text boxes on a Visual Basic form. Set the text boxes' OLEDragMode property to 1-Automatic and their OLEDropMode property to 2-Automatic, then run the form. You can now select a word and drag it from one text box to the other. You can also use this functionality to drag between a Visual Basic text box and Word (or any application that uses drag and drop).
31 January 1997
Save before you play in the API.
Save your work before working with the API. The Windows API functions are rich in possibilities. These libraries provide access to advanced functionality and you may want to experiment with API calls. But beware: A small misstep while using the API can crash your system, forcing you to reboot. To ensure the integrity of your work as you play with API functions, click Options on the Tools menu, then choose either the Save Before Run, Prompt or the Save Before Run, Don't Prompt option. Either way, Visual Basic will save your project before running it, and your work will be protected.
24 January 1997
Avoid misspelled variable names with Option Explicit.
Avoid misspelled variable names with Option Explicit. Visual Basic gives you the option of entering variable names on the fly. (When you do, Visual Basic assumes that your undeclared variables are of the variant type, unless you specify otherwise in a Def statement.) The problem with using undeclared variables is that it's all too tricky to trace. You can avoid this situation by placing an Option Explicit statement in the general declarations section of your module or form — the statement forces you to declare all variables. If your code includes any undeclared variables, you'll receive a compile time error.
13 January 1997
Creating Two Versions of One Project.
The MAK and VBP extensions give you flexibility to develop two versions of each project. A Visual Basic 4.0 project can have either the MAK or the VBP extension. You can install the professional edition of Visual Basic 4.0 as a 16-bit development platform, a 32-bit platform, or both. Choosing "both" installs the 16-bit version in one directory and the 32-bit version in another. After installation, the two versions function independently. By putting the proper associations in place, you can create two versions of the same project — a MAK and a VBP. They can share forms and modules by taking advantage of conditional compilation. Using the Make EXE File dialog box, you can assign the two versions different executable names, version numbers, and statistics.
6 January 1997
One of these Variable Names is not like the Others. In Visual Basic, consistent capitalization makes it easy to spot errors in variable names. You can capitalize Visual Basic variable names as you wish. However, the program will enforce consistency by changing all occurrences of a variable name to match the capitalization pattern last used. In other words, if you use the variable myVariable, then later type MyVariable, Visual Basic will adjust the first occurrence to match the second.

You can use this behavior to be sure your variable names are spelled correctly throughout your code. Change one occurrence of the name to all capital letters (for instance, MYVARIABLE) and all other occurrences will be automatically changed to match. Now, if you look through the code and see MyVarible, you know the name is spelled incorrectly.


Back to Top

CLICK HERE TO VISIT THE TOP 1000!      

C&D Programming Corp.
Attn: Code of the Week
PO Box 20128
Floral Park, NY 11002-0128
USA
Phone: 212-504-7945
Fax Number: 212-504-7945
info@codeoftheweek.com