All Products | Support | Search | microsoft.com Guide
Visual Basic Home | Events & Training | Product Support | MSDN Online | Developer Products |
Product
Information
Technical
Information
Technical FAQ
Technical Articles
Online Community
Tutorials
Tips and Tricks
Product Documentation
Product Support
Samples &
Downloads
News & Reviews
Registration
Past Tips of the
Week
The Visual Basic Tip of
the Week is provided by
ZD Journals, publishers of Inside Visual Basic, a monthly
publication for Visual Basic users. Sign up for your free
preview Issue today. Find out how to receive the Tip of the
Week in e-mail!
You can quickly navigate to past tips using the alphabetical
topic list below. The tips are also organized chronologically
further down on this page.
A better way to gather multi-selected Visual Basic ListBox
items
A caveat for the FileSystemObject Delete methods in Visual
Basic
A new Format function
Accept only numbers in a text field
Add a new line to existing textbox text
Add controls to a Visual Basic control array at run-time
Add Dithered Backgrounds to your Visual Basic Forms
Add pop-up menu support to the Rich Textbox control
Add Web mouseover effects to Visual Basic
Avoid API bit-masking comparison errors in Visual Basic
Avoid cascading UserControl Change() events
Avoid variable type comparison glitches in textboxes
Confirm Screen Resolution
Convert NULL Values to Empty Strings to Avoid Errors
Compact and repair Jet databases with DAO
Compact long Visual Basic filepaths with SHLWAPI library
Correctly pass variant array parameters in Visual Basic
Create templates from existing forms
Creating a incrementing number box
Creating a new context menu in editable controls
Creating Professional Documents with Code
Creating Win32 region windows
Display animated GIFs in Visual Basic
Display UserControl property settings in the Property Window
Don't lose focus in UserControls
Drag & Drop the real selected Visual Basic treeview node
Dragging items from a list to another one
Enabling the horizontal scrollbar in a RichTextbox control
Enhancing Browser Page Load Performance
Evaluate string formulas in Visual Basic
Finding the last day of the month
Force Visual Basic 6.0 to open maximized code windows
Generate temporary Visual Basic files with API
GETting the contents of a file
Globally replace text using just 5 lines of Visual Basic code
Hide the mouse cursor in a Visual Basic application
How to build a data-shaped SQL clause for Visual Basic
Implementing a "wait" function in Visual Basic
Importing Registry settings
Increase Your RAD-ness by Creating Your Own Visual Basic
5.0 Templates
Increment and decrement dates with the [+] and [-] keys
Keep Your Background Processes Running
Keeping track of Visual Basic source code builds
Labeling your forms
Let DateDiff() determine if two dates are in the same month
Let Visual Basic determine if the CD Rom drive contains media
Link Lotus Notes to Visual Basic 6.0
Maintain a Visual Basic DBGrid's runtime column widths
Manipulate your controls from the keyboard
Measuring a text extent
Move files to the Recycle Bin with Visual Basic and Windows
API
Nothing to declare?
Opening a browser to your homepage
Prevent drag and drop operations on Visual Basic treeview
root nodes
Parsing Using SPLIT Function
Put your Visual Basic application into deep sleep
Quick Custom Dialogs for DBGrid Cells
Quick Text Select On GotFocus
Read Registry values in Visual Basic without API
Referring to a DE Command's recordset in Visual Basic 6.0
Replace lengthy path strings with Visual Basic object variables
Retrieve a file's short name in Visual Basic without API
Retrieve subitem values from a Visual Basic ListView control
Scroll to a Visual Basic listview control's selected item
Showing long ListBox entries as a ToolTip
Simple file checking from anywhere
Spell check RTF documents in Visual Basic
Switching to Design View after Modifying ASP Script in Visual
InterDev
Take Advantage of Built-in OLE Drag and Drop
Uncover internal DLL functions with Dependency Walker
Update the Visual Basic 6.0 DataGrid control with recordset
changes
Use ADO's native OLEDB drivers instead of ODBC
Use FileDSNs to ease ODBC Installs
Use FreeFile to Prevent File Open Conflicts
Use ParamArray to Accept an Arbitrary Number of Parameters
Use Visual Basic's ADOX to determine if internal database
objects exist
Use the Timer control for longer than 1 minute
Use the Visual Basic 6.0 Split function to count substrings
Using Response.IsClientConnected Property to Determine
Browser Connection
Using Server.HTMLEncode() Function
Using the Alias Option to Prevent API Crashes
Visible Cues from a Minimized Form
Writing to the Windows NT event log
For the week of September 11th
How to build a data-shaped SQL clause for Visual Basic
Since it's introduction in ADO 2.0, data shaping has remained
largely on the fringes of Visual Basic arcanum. Relegated to
the back pages of musty manuals, you may have overlooked
this useful aspect of ADO. If you're not familiar with datashaping, in essence, it lets you create recordsets within
recordsets--or parent/child relationships--all with a single ADO
object. This means no messy joins, no complicated filtering,
and no need for spaghetti-code in presentation logic. Data
shaping reduces the amount of traffic crossing a network,
provides more flexibility when using aggregate functions, and
reduces overhead when interfacing with leading-edge tools
like XML.
To create a shaped recordset, you use a standard SQL
statement, along with three major keywords: SHAPE, APPEND,
and RELATE, like so
SHAPE {SELECT EmployeeID,FirstName, LastName
FROM Employees}
APPEND ({SELECT OrderID, shipname, EmployeeID
FROM orders} AS SomeAlias
RELATE EmployeeID TO EmployeeID);
The SHAPE keyword specifies and defines the parent
recordset. Once you create a parent object, you next APPEND
the child recordset. This clause uses a similar syntax as SHAPE
and contains the necessary SQL statement to create the child
recordset within the parent. In addition to the child recordset's
SQL statement, you must also indicate how you want the two
recordsets to RELATE.
For the week of August 28th
Add pop-up menu support to the Rich Textbox control
While Visual Basic provides an easy way to create shortcut
menus, some controls such as rich text boxes don't inherently
support pop-up menus. To overcome this obstacle, you can
take advantage of the MouseDown() event. Visual Basic
triggers this event when you press the mouse button. To
provide a pop-up menu, create a shortcut menu, then simply
call it in the control's MouseDown() event.
To see how this works, add a Rich Textbox control to a sample
form. Next, select Tools | Menu Editor from Visual Basic's IDE
menu bar, and create a simple menu with one or two items.
Then, switch to the form's code window, and enter
Private Sub RichTextBox1_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Me.PopupMenu Menu
End IF
End Sub
For the week of August 21st
Add Web mouseover effects to Visual Basic
One common effect found in sites all across the Web is what's
termed the mouseover effect. This effect usually provides
some form of limited animation in a Web page element. For
instance, when you move the mouse over a button, the button
changes color, giving it a glowing appearance. Given an
understanding of Visual Basic's mouse events, you can easily
supply these same effects in your own applications.
To imitate the same graphical effect in a Visual Basic project,
use the MouseMove() event. As its name implies, this event
lets you track the mouse's movement over controls, forms,
and MDIForms. For forms, this event follows the syntax:
Private Sub Form_MouseMove(button As Integer, _
shift As Integer, x As Single, y As Single)
Where button stores the current state of the mouse buttons;
shift indicates the state of [Shift], [Ctrl], and [Alt] keys; and x
and y the current mouse coordinates.
To illustrate, launch a new Visual Basic project and place a
command button on the default form. Next, set the control's
background color to yellow (&H0000FFFF&) and make the font
8 point. Finally, set the Style property to 1-Graphical so Visual
Basic will display the color. Now add the following code
Private Sub Command1_MouseMove(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
With Command1
.BackColor = vbGreen
.FontSize = 12
End With
End Sub
Now, when you run the project, the button turns green and
the font size increases when you move the mouse pointer over
it. To turn the button back to its original state when you move
the mouse pointer elsewhere, add the following event:
Private Sub Form_MouseMove(Button As Integer, Shift As _
Integer, X As Single, Y As Single)
With Command1
.BackColor = vbYellow
.FontSize = 8
End With
End Sub
For the week of August 14th
Move files to the Recycle Bin with Visual Basic and
Windows API
Want to delete a file and have it go into the recycle bin? The
Kill statement permanently deletes the file. Instead, try the
following:
Private Declare Function SHFileOperation Lib _
"shell32.dll" (ByRef lpFileOp As _
SHFILEOPSTRUCT) As Long
Private Const ERROR_SUCCESS = 0&
Private Const FO_COPY = &H2
Private Const FO_DELETE = &H3
Private Const FO_MOVE = &H1
Private Const FO_RENAME = &H4
Private Const FOF_ALLOWUNDO = &H40
Private Const FOF_CONFIRMMOUSE = &H2
Private Const FOF_FILESONLY = &H80
Private Const FOF_MULTIDESTFILES = &H1
Private Const FOF_NOCONFIRMATION = &H10
Private Const FOF_NOCONFIRMMKDIR = &H200
Private Const FOF_RENAMEONCOLLISION = &H8
Private Const FOF_SILENT = &H4
Private Const FOF_SIMPLEPROGRESS = &H100
Private Const FOF_WANTMAPPINGHANDLE = &H20
Private Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAnyOperationsAborted As Long
hNameMappings As Long
lpszProgressTitle As String '
FOF_SIMPLEPROGRESS
End Type
only used if
Next create a function called Recycle, like so
Public Sub Recycle(ByVal FileName As String)
Dim CFileStruct As SHFILEOPSTRUCT
With CFileStruct
.hwnd = Me.hwnd
.fFlags = FOF_ALLOWUNDO
.pFrom = FileName
.wFunc = FO_DELETE
End With
If SHFileOperation(CFileStruct) <> ERROR_SUCCESS Then
'An error occurred.
End If
End Sub
To test the procedure, create a dummy text file, drop a
command button onto a Visual Basic form, and then attach
the following code
Private Sub Command1_Click()
Recycle "c:\test.txt"
End Sub
When you click the button, Windows asks if you want to move
the file to the Recycle Bin.
For the week of August 7th
Avoid variable type comparison glitches in textboxes
When you retrieve a numeric value from a textbox, you may
want to compare it to some other preset value. For example,
consider the following code:
Select Case Text1.Text
Case 1 to 12
MsgBox "Acceptable Value"
Case Else
MsgBox "Unacceptable Value"
End Select
You might think that this code would compare a numeric value
in Text1 and return Acceptable Value for values 1 through 12,
and Unacceptable Value for all other numbers. Instead, this
code snippet displays the Acceptable Value message for only
1, 10, 11, and 12, but not 2, 3, 4, etc. That's because a
textbox's Text property returns the value as a string, and so
compares them as such in the Select Case statement.
To avoid this unexpected glitch, convert the numbers with the
Val() function. This function automatically converts a string
into the appropriate type: integer, long, single, or double. The
modified code would look as follows:
Select Case Val(Text1.Text)
Case 1 to 12
MsgBox "Acceptable Value"
Case Else
MsgBox "Unacceptable Value"
End Select
For the week of July 31st
Put your Visual Basic application into deep sleep
There may be occasions when you want an application to wait
for a specified period of time without performing activity or
wait loops. The Timer control can help, but only up to 60
seconds. The Sleep Windows API function lets you put the
application to sleep. Enter the following declaration into a
standard module.
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As
Long)
Then, simply call the function from your code, as in:
Sleep 5000
In this case, the 5000 milliseconds puts the application to bed
for 5 seconds. You can specify your own period of time,
though.
For the week of July 24th
Compact and repair Jet databases with DAO
Access's databases are typically reliable, but occasionally they
can get damaged. There are numerous reasons why, such as
powering down the computer without first closing the
database file or the system simply crashing. Another source of
problems for databases is excessive fragmentation-when
records are deleted from a database file, the file becomes
fragmented. Whatever the reason, once the database is
damaged, end-users are often left stranded until technical
support finds the time to help them. Fortunately, you can take
measures to help users quickly recover from such problems,
by providing built-in utilities that perform routine database
maintenance.
The DAO library provides two methods to perform the
necessary maintenance that keeps Access databases running
smoothly--RepairDatabase and CompactDatabase. The
RepairDatabase method uses the syntax
RepairDatabase dbname
where dbname is a string representing the full pathname of
the Access database (.MDB) that you need to repair. This
CompactDatabase method uses the following syntax:
CompactDatabase olddb, newdb, _
locale, options, password
You specify the full path and filename of your source database
as a string in the method's olddb property. Likewise, you
specify the destination of the compacted database with the
newdb property.
So, to use these statements, you could add code similar to:
RepairDatabase "C:\myData1.mdb"
CompactDatabase "C:\myData1.mdb", App.Path &
"\myDataNewName.mdb"
If you use DA0 3.6, then you can remove the RepairDatabase
statement. DAO 3.0 incorporates this functionality into the
CompactDatabase method-you can no longer compact and
repair databases as separate actions.
For the week of July 17th
Link Lotus Notes to Visual Basic 6.0
With the introduction of Lotus Notes and Domino Release
5.0.2b, you now have the ability to manipulate the Domino
object model via COM. As a result, you can use VB 6.0 to take
advantage of Lotus/Domino services and databases.
To do so, however, you'll need Lotus Notes client version
5.02.b (or higher), Domino Designer client, or Domino Server.
As with most Visual Basic object libraries, the programs need
not be running to use them. Lotus has plans to make this
runtime package distributable independent of its full software
installation.
Next, set a reference to the Notes back-end DLL, Lotus
Domino Objects. This object model conforms to a hierarchy
similar to CDONTS, as seen in the sample code, which displays
a message box with the first name in a Lotus Notes' address
book. Notice that before you can access any of the objects
within the NotesSession, you must initialize a session first.
Dim domSession As New Domino.NotesSession
Dim domDatabase As New Domino.NotesDatabase
Dim domDocument As NotesDocument
Dim domViewEntry As NotesViewEntry
Dim domView As NotesView
Dim domViewNav As NotesViewNavigator
Dim strName As String
domSession.Initialize
Set domDatabase = domSession.GetDatabase("", _
"names.nsf")
Set domView = domDatabase.GetView("Contacts")
' This view contains the list of names
Set domViewNav = domView.CreateViewNav
Set domViewEntry = domViewNav.GetFirstDocument()
Set domDocument = domViewEntry.Document
strName = domDocument.GetItemValue("FullName")(0)
MsgBox strName
Set domViewEntry = Nothing
Set domViewNav = Nothing
Set domView = Nothing
Set domDocument = Nothing
Set domDatabase = Nothing
Set domSession = Nothing
For the week of July 10th
Avoid cascading UserControl Change() events
When you expand one of Visual Basic's built in controls, avoid
building in a cascading Change event. This occurs when
internal UserControl code changes a constituent control's
value. Doing so triggers the constituent control's Change()
event. Most likely, you'll have also exposed this event to the
developer. If the developer has placed code in the
UserControl's Change() event, then this will be triggered as
well. For instance, suppose you create an ActiveX Control
project and add a standard textbox as a constituent control.
Next, you add the basic code:
Private mstrText As String
Public Event Change()
Private Sub Text1_Change()
MsgBox "Text1 Change"
RaiseEvent Change
End Sub
Public Property Get Text() As String
Text = mstrText
End Property
Public Property Let Text(Val As String)
mstrText = Val
End Property
Private Sub UserControl_ExitFocus()
Text1.Text = "Hello, " & Text1.Text
End Sub
Under this scenario, the UserControl will modify the textbox's
text whenever it loses the focus. However, suppose a
developer places the UserControl on a standard form and adds
the following code:
Dim X as Integer
Private Sub UserControl11_Change()
X = X + 1
MsgBox X
End Sub
Now, every time the UserControl loses focus, Visual Basic
increments X by one-probably not what the developer had in
mind.
To avoid the unintentional consequences cascading Change
events can cause, consider adding an internal public Boolean
variable to the UserControl that tracks internal changes vs.
external ones, like this:
Private blnInternal as Boolean
Private Sub Text1_Change()
If Not blnInternal Then
MsgBox "Text1 Change"
RaiseEvent Change
End If
End Sub
Private Sub UserControl_ExitFocus()
blnInternal = True
Text1.Text = "Hello, " & Text1.Text
blnInternal = False
End Sub
For the week of July 3rd
Accept only numbers in a text field
Often, to ensure that users enter only numbers in a text field,
you'll want to validate the text as they enter it. The textbox's
Change() event provides the best place to do so. However,
simply using the IsNumeric() function alone won't do the trick.
For instance, suppose you created the following procedure
Private Sub Text1_Change()
If Not IsNumeric(Text1.Text) Then
Text1.Text = ""
End If
Under these circumstances, if the user entered the number 333, the control wouldn't accept it because the beginning dash
isn't a number. Instead, consider using the following function
Private Sub Text1_Change()
If Not ValidateNumeric(Text1.Text) Then
Text1.Text = ""
End If
End Sub
Private Function ValidateNumeric(strText As String) _
As Boolean
ValidateNumeric = CBool(strText = "" _
Or strText = "-" _
Or strText = "-." _
Or strText = "." _
Or IsNumeric(strText))
End Function
For the week of June 26th
Display UserControl property settings in the Property
Window
At design-time, when you set a control's property value,
Visual Basic often provides a list of valid settings in a
dropdown list. To display such a list for your own custom
UserControl property settings, you'll need to add an
enumerated property to your ActiveX Control project. To do
so, declare the property's potential values with the Enum
statement, like so
Public Enum UCBorderStyles
UCBorderNone = 0
UCBorderFlat = 1
UCBorderThin = 2
UCBorderFrame = 3
UCBorderThick = 4
End Enum
Once you've established the potential values, you'll need to
use the enumerated type in the Property Let and Get
statements, as in
Private mintBorderStyle As UCBorderStyles
Public Property Get BorderStyle() As UCBorderStyles
BorderStyle = mintBorderStyle
End Property
Public Property Let BorderStyle(val As UCBorderStyles)
mintBorderStyle = val
End Property
Now, when Visual Basic instantiates the control at design
time, the valid UCBorderStyles will appear in the Property
Window's dropdown list for the BorderStyle property.
For the week of June 19th
Don't lose focus in UserControls
Typically, to determine when a UserControl gains and loses
focus, you might think to use the standard GotFocus and
LostFocus events. However, in UserControls these two events
aren't always reliable. There are situations where a control will
lose the focus without firing the LostFocus event (for example,
when Alt+Tabbing to another application), and also get the
focus without firing the GotFocus event. As a result, your best
bet for monitoring the focus status is to insert code in the
UserControl's EnterFocus and ExitFocus events.
For the week of June 12th
Uncover internal DLL functions with Dependency Walker
While the Windows API functions are fairly well documented,
you may come across other DLL files that remain a mystery.
For example, suppose you want to incorporate the MIDAS
digital audio player into your application. The help files that
come with this free DLL list all the important external function
names. However, because the DLL doesn't support Visual
Basic, you must hook into the DLL with API declarations. The
internal names supported in this library aren't in the help files.
To unravel this mystery, you can use the Dependency Walker,
a handy utility that comes with Visual Studio (appears as
Depends on the Windows program menu). Simply point the
utility to the DLL in question, and it will list all the internal file
names that you'll need to refer to in your API declarations. For
example, in the MIDAS DLL, you use a function called
MIDASplayModule to play a sound module. However, the
internal name for the function is _MIDASplayModule@8. As a
result, you must declare the function in Visual Basic like so
Declare Function MIDASplayModule Lib "midas11.dll" Alias _
"_MIDASplayModule@8" (ByVal module As Long, ByVal
loopSong _
As Boolean) As Long
Using the Dependency Walker on MIDAS, you could quickly
and easily determine the library's internal function names.
For the week of June 5th
A better way to gather multi-selected Visual Basic
ListBox items
Conventional Visual Basic wisdom states that in order to
gather the selected items from a multi-select ListBox, you
should loop through all the items and test the Selected
property. As with all loops, however, this can potentially bog
down slower CPU's. As a much faster and more elegant
alternative, you can use the SendMessage() API function
instead.
As you probably know, this function lets you send a message
to one or more windows. The declaration statement conforms
to the following syntax:
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
Since we want to gather the listbox's selected items, we'll
send the LB_GETSELITEMS constant in the wMsg argument,
which you declare like so:
Private Const LB_GETSELITEMS = &H191
In essence, the LB_GETSELITEMS message fills an array with
the index numbers of all the selected items. As a result, you
must pass two additional arguments with SendMessage(). The
first argument should contain the maximum number of
selected items. To retrieve this value, you can simply use the
listbox's SelCount property. The second argument should hold
the array variable you want to fill with index values. The
following example shows how you might use this function:
Dim ItemIndexes() As Long, x As Integer, iNumItems As
Integer
iNumItems = ThisBox.SelCount
If iNumItems Then
ReDim ItemIndexes(iNumItems - 1)
SendMessage ListBox1.hwnd, LB_GETSELITEMS, iNumItems, _
ItemIndexes(0)
End If
For x = 0 To iNumItems - 1
MsgBox ListBox1.List(ItemIndexes(x))
Next x
After being passed to the SendMessage function, iNumItems
holds the total number of selected items, and the ItemIndexes
array holds the selected item index values. Notice, that you
must pass a pointer to the ItemIndexes array, and not the
array itself. Thus, we passed ItemIndexes(0) into the
SendMessage function, not ItemIndexes().
For the week of May 22nd
Spell check RTF documents in Visual Basic
To spell check RTF documents, you could resort to embedding
Word into your application. However, if you plan to use the
WebBrowser control, there's no need to program Word for
spell checking. That's because the WebBrowser control
provides this functionality for you. To access it, you use the
WebBrowser control's ExecWB() method with the
OLECMDID_SPELL flag. To illustrate, add the WebBrowser
control to a form, then add the following code to the form's
Load() event
WebBrowser1.Navigate "D:\Internet\spell.rtf"
Replace the path with any string that points to an RTF file.
Next, add a command button, and enter this code in its Click()
event:
WebBrowser1.ExecWB OLECMDID_SPELL, OLECMDEXECOPT_DODEFAULT
Run the project. The WebBrowser displays the RTF file, and
when you click the command button, VB runs through the
normal spell check operation.
For the week of May 15th
Compact long Visual Basic filepaths with SHLWAPI
library
The PathCompactPath function in SHLWAPI provides one way
to compact long filenames. It does so by replacing a portion of
the pathname with an ellipsis (...). This function uses the
following API declaration statement:
Private Declare Function _
PathCompactPath Lib "shlwapi"_
Alias "PathCompactPathA" _
(ByVal hDC As Long, ByVal _
lpszPath As String, _
ByVal dx As Long) As Long
As you can see, the PathCompactPath function requires three
arguments. The first argument contains a device context
handle. The second argument holds the address of the
pathname you want to use. The third argument contains the
width in pixels of the spot in which you want the pathname to
fit. So, to place a compacted filename in a label named
lblEllipsis, place the following in a command button's Click()
event:
Private Sub Command1_Click()
Dim lhDC As Long, lCtlWidth As Long
Dim FileSpec As String
FileSpec =
"C:\MyFolder\VisualBasic\MyReallyWayTooLongFolderName\" _
& "ButWhoCares\IhaveTheAPI.doc"
Me.ScaleMode = vbPixels
lCtlWidth = lblEllipsis.Width - Me.DrawWidth
lhDC = Me.hDC
PathCompactPath lhDC, FileSpec, lCtlWidth
lblEllipsis.Caption = FileSpec
End Sub
For the week of May 8th
Referring to a DE Command's recordset in Visual Basic
6.0
Each Command object in Visual Basic 6.0's new Data
Environment also has an associated recordset. In code, you
refer to this object by preceding the Command object's name
with rs. So, for example, if your Data Environment contains a
Command named cmdSomeQuery, then to refer to the
resulting recordset, you'd use something like this:
Set rst = DataEnvironment1.rscmdSomeQuery
For the week of May 1st
Read Registry values in Visual Basic without API
Often you'll want to manipulate the Windows registry in Visual
Basic without resorting to lengthy API calls. Fortunately you
can with the Registry Access Functions (RegObj.dll) library.
This DLL lets you create a Registry object with which you can
manipulate specific keys. For example, in a previous tip we
showed you how to use the WebBrowser control to display an
animated GIF. Unfortunately, the WebBrowser is only
available if the target machine also has Internet Explorer
installed. As a result, you may want to display an alternative
image if Internet Explorer isn't available. To determine if IE is
installed on the target Windows 95 machine, first set a
reference in your project to Registry Access Functions. Then
use code similar to that below:
Dim myReg As New Registry, KeyFound As Boolean
Dim HasIE As Boolean, sValue As String
sValue = ""
KeyFound = myReg.GetKeyValue(HKEY_LOCAL_MACHINE, _
"Software\Microsoft\Windows\CurrentVersion\" & _
"App Paths\IEXPLORE.EXE", "Path", sValue)
If KeyFound Then HasIE = (sValue <> "")
If HasIE Then MsgBox sValue 'contains the path to IE
For the week of April 10th
Display animated GIFs in Visual Basic
While the Picture ActiveX control offers a great way to display
graphics, it only shows the first image in an animated GIF. To
display a fully animated GIF, without rebuilding the entire
graphic frame by frame, you can use the WebBrowser control
(just keep in mind that this control isn't available to machines
without IE 3.0 or greater). To do so, select the Microsoft
Internet Controls component. When you do, the WebBrowser
control appears on Visual Basic's toolbar. Drop the control
onto a form, then in the form's Load() event place the
following code:
WebBrowser1.Navigate "C:\Internet\anim.gif"
Where the filespec points to a valid animated GIF path or URL.
When you run the program, Visual Basic displays the GIF.
Unfortunately, the WebBrowser also displays a right-hand
scroll bar--probably not what you want for a decorative image.
Believe or not, you can turn this scrollbar off just like you
would normally via HTML, as in:
WebBrowser1.Navigate "about:<html><body scroll='no'>
<img src='D:\Internet\anim.gif'></img></body></html>"
Now when you run the form, Visual Basic displays the image
sans scrollbar.
For the week of April 3rd
Use Visual Basic's ADOX to determine if internal
database objects exist
Soon after ADO's release, Microsoft created an extension to
the object library called ActiveX Data Objects Extensions, or
ADOX. This library includes most of the DAO features missing
from standard ADO, including objects related to a database's
schema. With ADOX you can easily determine if a database
contains a specific table, view, or query.
To do so, set a reference to Microsoft ADO Ext. for DDL and
Security. For schema purposes, the ADOX consists of a
Catalog object, which contains the object collections that
describe the database, tables and views among them. To test
for an existing table in the Tables collection, you can either
iterate through the collection and check each item's name
against the test string; or you can use our favorite method, as
seen in the following code:
Dim cat As ADOX.Catalog
Dim tbl As ADOX.Table
Dim con As New ADODB.Connection
con.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.3.51;" _
& "Data Source=C:\Program Files\Microsoft Visual
Studio\VB98\Biblio.mdb"
con.Open
Set cat = New ADOX.Catalog
Set cat.ActiveConnection = con
On Error Resume Next
Set tbl = cat.Tables("MyTable")
If tbl Is Nothing Then
MsgBox "MyTable doesn't exist"
Else
MsgBox "MyTable exists"
Set tbl = Nothing
End If
bar, or click on screen objects.
For the week of March 27th
Hide the mouse cursor in a Visual Basic application
The ShowCursor API function provides a quick way to hide the
mouse cursor. It takes the following declaration statement
Private Declare Function ShowCursor Lib "user32" _
(ByVal bShow As Long) As Long
When you enter 0 for the bShow argument, the mouse cursor
disappears. Enter -1 to make the mouse reappear. Just be
aware when you use this function, however, that just because
you hide the mouse pointer, doesn't mean it's disabled. To see
what we mean, add the above declaration and the following
code to a form.
Dim blnShow As Boolean
Private Sub Form_Click()
blnShow = Not bln
ShowShowCursor blnShow
End Sub
Private Sub Form_Load()
blnShow = True
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode
As Integer)
If Not blnShow Then ShowCursor TrueEnd
SubNow, run the project.
When you click the form, Visual Basic toggles off the cursor's
visibility. Click the form once more, and the mouse cursor
reappears. If the mouse cursor had been truly disabled, you
wouldn't have been able to make the mouse cursor reappear
because the click wouldn't have registered. Now, click the
form so the mouse cursor disappears, and move the mouse
towards the IDE's menu bar. As the invisible mouse cursor
passes over each enabled button, it raises, ready to be
clicked. In fact, you can still use the mouse to choose options
from the menu bar, or click on screen objects.
For the week of March 20th
Evaluate string formulas in Visual Basic
If you've come to Visual Basic from Microsoft Access, you
probably miss the handy Eval() method. This method
evaluates a supplied string as though it were code. As a
result, you could easily evaluate mathematical expressions
passed as a string, like so:
iResult = Eval("(2 * 3) + 5)")
which fills iResult with the value 11.
To achieve this same functionality in Visual Basic, you've no
doubt resorted to complicated string parsing functions. Or
perhaps you added Access' DLL to your project, which may
have seemed like an awful lot of DLL for such a simple
method.Now, though, you'll be happy to know that you can
use the Eval() method without a lot of overhead. Microsoft
provides this functionality in its Script Control. This very
lightweight ActiveX component is available so you can add
end-user scripting ability to your applications. However, as a
result, it also comes with an Eval method. Adding this
component to your project provides very little overhead and
gives you the ability to evaluate mathematical strings.To
download this OCX, visit
http://msdn.microsoft.com/scripting/. Select the Script
Control link, then follow the Download instructions. The
following code shows the simple Visual Basic we added to a
command button's click event. The SC1 script control
evaluates a mathematical formula in the txtFormula textbox.
Private Sub Command1_Click()
MsgBox txtFormula & " = " & SC1.Eval(txtFormula)
End Sub
For the week of March 13th
Scroll to a Visual Basic listview control's selected item
The listview control is a great way to associate items with
icons, pictures, or in report rows. This control allows you to
programmatically select an item in the list. However, just
because Visual Basic selects an item, doesn't always mean
that it will be visible to a user. For example, if you have many
items displayed in the control, you might need to use the
scroll bar to display an item at the bottom of the list.
Fortunately, the listview control also makes it easy to
programmatically scroll to a selected item. Each item in the
list has an EnsureVisible method. Just as you'd expect, when
you call this method, it forces the control to display the item
in the visible portion of the listview.To illustrate, drop a
listview control onto a default form, then right-click on it and
select Properties from the shortcut menu. In the Properties
Pages dialog box, change the control's View property to 3 lvwReport. Next, click on the Column Headers tab, click Insert
Column, and enter "Which Foo?" in the Text field. Click OK to
complete the process.
Finally, add the following code to the form:
Private Sub Form_Load()
Dim x As Integer
With ListView1
For x = 1 To 20
.ListItems.Add Key:="Item " & x, Text:="Item" & x
Next x
.SelectedItem = .ListItems("foo20")
.SelectedItem.EnsureVisible
End With
End Sub
When you run the project, Visual Basic opens the form and
displays the 20th item in this list.
For the week of March 6th
Avoid API bit-masking comparison errors in Visual Basic
Often when you use API functions, you'll want to determine if
the results contain a specific flag. To do so, you use the And
operator and mask the specific flag for which you're testing.
For example, suppose you want to determine if the current
window is maximized. First, get the current window's settings
with the GetWindowLong() API function, which you declare in
a standard module like so
View Source
When you run the form and click the button, the code
determines if the style value contains the flag's bit value. If it
does, then the boolean comparison returns a number, which
Visual Basic interprets as True. If not, the comparison returns
0, or false.
Errors can occur, however, when you try to test for the
exclusion of a specific flag. For example, suppose you want to
perform actions when the window isn't maximized. You might
think to simply use
If Not (lWinStyle And WS_MAXIMIZE) Then
(Of course, in this particular case, you could simply test for
the WS_MINIMIZE flag, but there are times when API
functions don't have a flag representing an opposing setting)
Unfortunately, this condition statement always returns True.
That's because when you use Not on a number, Visual Basic
returns the opposite value of that number minus one. For
instance, the expression Not 15 returns -16, which as you
know Visual Basic interprets as True. With regard to the bit
masking example, if the window is maximized, Not (lWinStyle
And WS_MAXIMIZE) evaluates to a non-zero number, which
again Visual Basic evaluates as True.
To get around this minor glitch, you can use one of the
following two statments:
If Not Cbool(lWinStyle And WS_MAXIMIZE) Then
or
If Not ((lWinStyle And WS_MAXIMIZE)<>0) Then
For the week of February 28th
Correctly pass variant array parameters in Visual Basic
If you create a procedure that will accept both standard arrays
as well as those created from the Spit() and Array() functions,
then you'll definitely want to type the argument as a variant,
not an array, as in
Sub FooList ( MyArrayList as Variant)
instead of
Sub FooList (MyArrayList() as Variant)
Why? Well, both the Split() and Array() functions create
variant arrays-that is, a variant variable filled with an array
subtype. And even though you manipulate them the same
way, Visual Basic doesn't consider an array of variants and a
variant array the same thing. So, if your procedure expects a
regular array and you pass it a variant array created from the
Split() or Array() function, you'll get a type mismatch error.
On the other hand, Visual Basic does let you pass a regular
array into a variant parameter-which makes sense when you
consider a variant's universal nature.
For the week of February 21st
Generate temporary Visual Basic files with API
If you've ever used Word, or any other Office application, you
probably noticed that each time you open a file, Office creates
a temporary file to store changes. You may have wondered
how to generate random temporary file names in your own
Visual Basic application. To do so, use the GetTempFileName
API function, which you declare in a standard module, like so
Public Declare Function GetTempFileName Lib "kernel32" _
Alias "GetTempFileNameA" (ByVal lpszPath As String, _
ByVal lpPrefixString As String, ByVal wUnique As
Long, _
ByVal lpTempFileName As String) As Long
Pass the full path name in the lpszPath argument. The
lpPrefixString lets you add a three letter prefix to the
beginning of the filename, and wUnique tells Windows to
either create a random file name (0 setting) or use the
number you supply. The lpTempFileName, of course, contains
the new temporary filename. As an example, place the API
declaration above in a standard module, then add the
following function
Private Function GenTempName(sPath As String)
Dim sPrefix As String
Dim lUnique As Long
Dim sTempFileName As String
If IsEmpty(sPath) Then sPath = "D:\Articles\IVB"
sPrefix = "fVB"
lUnique = 0
sTempFileName = Space$(100)
GetTempFileName sPath, sPrefix, lUnique, sTempFileName
sTempFileName = Mid$(sTempFileName, 1,
InStr(sTempFileName, Chr$(0)) - 1)
GenTempName = sTempFileName
End Function
Now, open a new form and add the following code to its
Click() event. (Replace D:\Articles\IVB with any valid path)
MsgBox GenTempName("D:\Articles\IVB")
For more information on generating temporary Visual Basic
files with API, please see the following article in the Microsoft
Knowlege Base:
Q195763 - HOWTO: Use GetTempFileName API to Create a
Unique Temporary File
For the week of February 14th
Globally replace text using just 5 lines of Visual Basic
code
If you've ever tried to implement a text search and replace
function in Visual Basic, you probably resorted to lengthy
parsing loops that used Instr() and an entire host of string
functions. If so, you'll be glad to know that there's a much
easier way.
With the advent of VBScript 5.0, Microsoft introduced the
Regular Expression engine, which you can also use in Visual
Basic. If you've used Perl or JavaScript, you may be familiar
with these pattern-matching powerhouses. In a nutshell,
regular expressions let you define a pattern, literal or
representative, which you can then match against a second
string. For example, the literal pattern 'abc' as a regular
expression would find a match in 'dabcef', 'abcdef', or 'defabc'.
To further refine a regular expression, the Regular Expression
engine offers a host of special metacharacters, similar to
wildcard characters. For example, using these metacharacters,
you could search for any word that began with a letter and
ended in a digit. To view these metacharacters and their uses,
visit Microsoft Windows Script Technologies.
then search in the VBScript documentation for the RegExp
object's Pattern property.
To create a simple find and replace subroutine, first download
the VBScript DLL from
http://www.microsoft.com/msdownload/vbscript/scripting.asp.
Once you've registered the dll on your system, in your Visual
Basic project set a reference to Microsoft VBScript Regular
Expressions. Now, via code, create a RegExp object, like so
Set MyReg = new RegExp
Next, set the object's properties.
MyReg.IgnoreCase = True
MyReg.Global = True
MyReg.Pattern = "abc"
Here, we've used a literal string to create a global, caseinsensitive pattern. Finally, you execute the object's Replace
method on the target string, as in
txtSearchText = MyReg.Replace(txtSearchText, "def")
That's *all* there is to it! This example would replace "abc"
with "def" wherever it occurred within txtSeartText. To
execute the replace only on the first matching string, set the
Global property to False.
For the week of February 7th
Retrieve a file's short name in Visual Basic without API
Many times, you'll need to reference a file by it's 8.3 file
naming convention. Chances are, you've seen these file
names in MSDOS. For instance, under this convention, the
Program Files folder becomes Progra~1. You'll be happy to
know that you can retrieve this short path name without
resorting to the GetShortPathName API function. As an
alternative, the new Scripting Runtime library offers the
ShortPath property, which it provides for both File and Folder
objects. To obtain a file's short path name, simply add a
project Reference to the Microsoft Scripting Runtime, then use
code similar to:
Private Sub Form_Load()
Dim fsoFile As File, fso As FileSystemObject
Set fso = New FileSystemObject
Set fsoFile = fso.GetFile("C:\MyReallyLongName.txt")
MsgBox fsoFile.ShortPath
Set fsoFile = Nothing
Set fso = Nothing
End Sub
For the week of January 31st
A caveat for the FileSystemObject Delete methods in
Visual Basic
As you know, the Microsoft Scripting Runtime object library
makes it easy to manipulate files and folders. With the
DeleteFolder and DeleteFile methods, you can eliminate
unwanted items. However, these methods will abort if they
encounter an error--and they don't rollback the changes they
made up to that point. For instance, if a method deletes two
folders out of ten and an error occurs, Visual Basic aborts the
operation and only the first two items will have been deleted.
Several FileSystemObject methods operate this way.
For the week of January 24th
Maintain a Visual Basic DBGrid's runtime column widths
The DBGrid is a great way to display data as a familiar gridstyle output. However, if you change the column widths on the
grid at runtime, Visual Basic doesn't use these new widths the
next time you run the application. Fortunately, the following
procedure will maintain the column widths for you:
Sub DBGridLayout(Operation As String)
'save width of columnsDim lWidth As Long
Dim clm As Column
Dim lDefWidth As Long
l
DefWidth = DBGrid1.DefColWidth
For Each clm In DBGrid1.Columns
With clm
Select Case LCase(Operation)
Case "save"
lWidth = .Width
SaveSetting App.Title, "Cols", CStr(.ColIndex), _
lWidth
Case "load"
lWidth = GetSetting(App.Title, "Cols", _
CStr(.ColIndex), lDefWidth)
.Width = lWidth
End Select
End With
Next clm
End Sub
As you can see, this procedure uses the SaveSetting and
GetSetting functions to store the current width values in Visual
Basic's portion of the registry. To use the procedure, call it
from the parent form's Load and Unload events. Then, indicate
which operation you want the procedure to perform, as in:
Private Sub Form_Load()
DBGridLayout "Load"
End Sub
Private Sub Form_Unload(Cancel As Integer)
DBGridLayout "Save"
End Sub
For the week of January 17th
Prevent drag and drop operations on Visual Basic
treeview root nodes
Often when you allow drag and drop operations in a treeview
control, you won't want a root node dragged to another level.
For instance, if you filled the control with departments and
their employees, you wouldn't want a department node placed
under an employee. To prevent this from happening, you can
use the OLEStartDrag event to provide validation. For
example, testing for the Parent property provides a quick way
determine a root node. As you know, the Parent property
returns an item's Parent node. So, if the property returns
nothing, then the target node to be dragged is really a root
node. Using our previous tip for assigning a treeview's current
node, you can use code like the following:
Option Explicit
Public dragNode As Node, hilitNode As Node
Private Sub TreeView1_MouseDown(Button As Integer, Shift
As Integer, _
x As Single, y As Single)
Set dragNode = TreeView1.HitTest(x, y)
End Sub
Private Sub TreeView1_OLEStartDrag(Data As
MSComctlLib.DataObject, _
AllowedEffects As Long)
If dragNode.Parent Is Nothing Then Set dragNode = Nothing
End Sub
Then in the OLEDragOver and OLEDragDrop events, create
conditional statements to test if the dragNode is nothing, then
perform the drag and drop operations accordingly. For
example, the OLEDragOver event might look like this:
Private Sub TreeView1_OLEDragOver(Data As
MSComctlLib.DataObject, _
Effect As Long, Button As Integer, Shift As Integer,
_
x As Single, y As Single, State As Integer)
If Not dragNode Is Nothing Then
TreeView1.DropHighlight = TreeView1.HitTest(x, y)
End If
End Sub
For the week of January 10th
Update the Visual Basic 6.0 DataGrid control with
recordset changes
The DataGrid control is a great way to display multiple data
rows in a table-like format. Unfortunately, the control is also
plagued with bugs. Some have been fixed by Service Patch 3,
but some haven't. For instance, if you connect the DataGrid to
a DataEnvironment, then make changes to the underlying
recordset and refresh the DataGrid with the Refresh method,
the control still doesn't reflect the changes. Unfortunately, the
Refresh method doesn't work when the control's DataSource is
a DataEnvironment. Instead, to show the updated recordset
changes, first update the DataEnvironment's recordset, then
rebind the DataGrid to the DataEnvironment. So, if you have a
Refresh button, it's click event might look like this:
DataEnvironment1.rsCommand1.Requery
Set DataGrid1.DataSource = DataEnvironment1
Now, when you click the Refresh button, the code rebinds the
DataEnvironment to the DataGrid and refills the control with
the refreshed data.
For the week of January 3rd
Drag & Drop the real selected Visual Basic treeview
node
Enabling drag and drop in the treeview control can seem
deceptively easy. The property sheet displays two properties
for altering this capability. However, as you probably know, it
takes a little code behind the scenes to actually make the drag
and drop work. No doubt, you've seen the control's
OLEStartDrag, OLEDragOver, and OLEDragDrop events, which
you use to implement this technique. The basic idea behind a
drag and drop code procedure is to set a public node variable
equal to the currently selected node, highlight each node the
mouse passes over during the OLEDragOver event, then add
the dragged item to the node under the mouse pointer to
complete the procedure. With this in mind, after first setting
the control's OLEDragMode to 1-ccOLEDragAutomatic, (and
filling it with items, of course) you might think to initiate the
OLEStartDrag event like so:
Option Explicit
Public dragNode As Node, hilitNode As Node
Private Sub TreeView1_OLEStartDrag(Data As
MSComctlLib.DataObject, _
AllowedEffects As Long)
Set dragNode = Treeview1.SelectedNode
End Sub
Here, the code sets the node to be dragged equal to the
currently selected node. Unfortunately, this doesn't work.
That's because, a node only becomes a selected node after
the MouseUp event. And as you know, you initiate a drag by
holding the mouse button down. As is, the above code actually
selects the previously selected node instead. So, to indicate
the correct node, use the HitTest method in the treeview's
MouseDown event, like so:
Private Sub TreeView1_MouseDown(Button As Integer, Shift
As Integer, _
x As Single, y As Single)
Set dragNode = TreeView1.HitTest(x, y)
End Sub
For the week of December 6th
Replace lengthy path strings with Visual Basic object
variables
Many methods that manipulate a drive, folder, or file in the
MS Scripting Runtime library require a filespec argument--the
item's path, represented as a string. However, because the
Path property is the default property for these three items
(drive, folder, and file), you can also use object variables in
place of the path strings. So for instance, to copy one folder to
another using object variables, you could use
fldr1.Copy fldr2, False
or
MyFSO.CopyFile file1, file2, False
For the Week of November 22nd
Use ADO's native OLEDB drivers instead of ODBC
When you create a connection string, ADO gives you a choice
between indicating a data source driver as either a Driver, as
in
Driver={SQL Server};DBQ=database_file
or a Provider, such as
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=database_name
However, when you use the first option, ADO uses older ODBC
drivers to connect to the data source; whereas the second
form uses OLEDB, which is ADO's native data access interface.
For this reason, you should use the Provider option whenever
possible. Such native OLEDB drivers exist for SQL Server,
Index Server, Site Server Search, and Oracle, among others.
When using the provider method and distributing the
application, the correct version of MDAC must be distributed
as well, as they are not compatible. The MDAC 2.0 series
carries the OLEDB 3.51 provider, the MDAC 2.1 series carries
the OLEDB 4.0 provider.
For the Week of November 15th
Let Visual Basic determine if the CD Rom drive contains
media
To quickly determine if the CD Rom drive contains media, use
the Scripting Runtime library's IsReady property for the Drive
object. For CD Rom drives, this property returns True only if
the drive contains the appropriate media. To take advantage
of this handy property, add a Reference to Microsoft Scripting
Runtime library (scrrun.dll). Next, create a Drive variable
based on the CD Rom drive, and test the IsReady property, as
shown below:
Dim FSO As FileSystemObject
Dim aDrive As Drive
Set FSO = New FileSystemObject
For Each aDrive In FSO.Drives
If aDrive.DriveType = CDRom And aDrive.IsReady = False
Then
MsgBox "Please enter a CD."
Exit For
ElseIf aDrive.DriveType = CDRom Then
MsgBox aDrive.VolumeName
Exit For
End If
Next
Set FSO = Nothing
For the Week of November 8th
Retrieve subitem values from a Visual Basic ListView
control
When you use the ListView control in Report view, the control
shows a table-like list. It's the same view that appears in the
file dialog boxes (Open, Save, etc.) when you click the Details
button. Each row displays additional subitem information
about the main item. For example, in the file dialog boxes, the
main item is the file itself, while the Size and Type columns
are the subitems. When you use the ListView control in your
own applications, Visual Basic makes it easy to determine
which item you've selected. When you select an item in Report
view, Visual Basic triggers the ItemClick event, which passes a
ListItem object (the item you just clicked). From this object,
you can determine its value. So, for example, the entire event
procedure might look like this
Private Sub lstvwFiles_ItemClick _
ByVal Item As MSComctlLib.ListItem)
strFileSelected = Item
End Sub
This statement would pass the selected item's value (Value
being the object's default property) into the strFileSelected
variable. However, you may have wondered how to retrieve
the Item's associated subitem values. Fortunately, Visual
Basic provides the ListSubItems collection, which contains all
the subitems of an individual item. So, continuing with the
example above, the Size and Type items are both subitems of
the main File item. To ascertain the values of these subitems,
you simply loop through the collection, like so
Private Sub lstvwFiles_ItemClick _
(ByVal Item As MSComctlLib.ListItem)
Dim itm As ListSubItem
Dim strSubs As String
MsgBox "ItemClicked: " & Item
For Each itm In Item.ListSubItems
strSubs = strSubs & itm & ": "
Next itm
MsgBox "SubItems: " & strSubs
End Sub
For the Week of October 11th
Add controls to a Visual Basic control array at run-time
As you probably know, a control array lets you create controls
that share the same name and events. They also use fewer
resources than do the same number of controls not part of a
control array. Often, you may want to add a control, such as a
button, to a control array at runtime. To do so, you use the
Load statement, which takes the following syntax.
Load object(index)
where object is the name of the control array, and index is the
index number of the new control you want to add. In order to
add controls to a control array at runtime, however, you must
have at least one control already in the array, (with it's index
property set-most likely to 0). Visual Basic only allows 32,767
controls in an array. For example, suppose you have a form
with a button control array named cmdBtn. On the button's
Click event, you want to add another button to the form. To
illustrate, open a new project and add a command button to
the default form. In the Properties Window, enter 0 for the
control's Index. When you do, Visual Basic transforms the
button into a control array. Now, add the following code to the
form:
Private Sub cmdBtn_Click(Index As Integer)
Dim btn As CommandButton
Dim iIndex As Integer
iIndex = cmdBtn.Count
If iIndex <= 32767 Then
Load cmdBtn(iIndex)
Set btn = cmdBtn(iIndex)
With btn
.Top = cmdBtn(iIndex - 1).Top + 620
.Caption = "Command" & iIndex + 1
.Visible = True
End With
Set btn = Nothing
End If
End Sub
For the Week of October 4th
Use the Visual Basic 6.0 Split function to count
substrings
As we mentioned in a previous tip, Visual Basic 6.0 introduced
the Split function, which provides a new way to parse strings.
With it, you indicate a delimiter within a string, and Visual
Basic fills a one-dimensional array with the substrings.
However, in addition to the functionality described above, you
can also use the Split function as a quick way to determine
the number of substrings within a larger string. For example,
suppose you want to determine the number of times 'sea'
appears in the string "She sells seashells by the seashore." To
do so, simply perform the split, and use the UBound function
to count the number of elements in the resultant array, as in
strTungTied = "She sells seashells by the seashore."
arySea = Split(strTungTied, "sea")
MsgBox "'Sea' appears in '" & strTungTied _
& "' " & UBound(arySea) & " times."
When you run this code snippet, Visual Basic informs you that
'sea' appears in the phrase twice.
For the Week of September 20th
Let DateDiff() determine if two dates are in the same
month
To determine if two dates are in the same month, your first
instinct may be to simply use the Month() function on each
date, then compare the two resulting numbers. However,
under these circumstances, the comparison would equate
1/1/2000 with 1/1/1999. Instead, the DateDiff() function
provides one quick way to make this determination, like so:
DateDiff("m", Date1, Date2)
In this expression, the DateDiff() function finds the difference
in calendar months between the two dates. If the expression
returns a zero, then the two dates are in the same calendar
month. To include this feature in an conditional expression,
you could use the following in a query:
If DateDiff("m", Date1, Date2) Then
'Month's are different
Else
'Month's are same
End If
For the Week of September 13th
Force Visual Basic 6.0 to open maximized code windows
While Visual Basic 5.0 was very good at remembering how you
preferred the IDE windows-maximized or normal. Visual Basic
6.0 isn't. It always opens the Code and Object windows in
normal view. Fortunately, you can modify this behavior with a
minor tweak to the Windows Registry so that the IDE always
opens these two windows maximized. Unfortunately, when
you make these changes, Visual Basic 6.0 will ALWAYS open
them maximized-it still won't remember your preferences
between sessions.
Before we begin, take note that altering the Registry is risky
business and you should always make a back-up copy of the
settings so that you can restore them if something untoward
happens. That said, to force Visual Basic 6.0 to open a
maximized Code or Object window, you add a new value
called MDIMaximized to the following Registry key:
HKEY_CURRENT_USER/Software/Microsoft/Visual
Basic/6.0/MDIMaximized = "1"
To do so, in Windows click the Start button and select Run.
Enter RegEdit in the Run dialog box, then click OK. When
Windows displays the system registry, navigate through the
keys until you've found the Visual Basic 6.0 folder. Next, rightclick anywhere in the right-hand pane and select New/ String
Value from the shortcut menu. Enter MDIMaximized as the
name and press [Enter]. Now, right-click on MDIMaximized
and select Modify from the shortcut menu. Finally, in the Edit
String dialog box, enter 1 for the value and click OK. When
you do, Windows assigns the value to MDIMaximized. That's
all there is to it! Close the registry and open a Code or Object
window in a Visual Basic 6.0 project. The IDE displays them
maximized.
For the Week of September 6th
Add a new line to existing textbox text
Often, you may want to append additional information to
existing text within a multiline textbox. For instance, suppose
you want to add the string "Updated: " followed by the current
date. To do so, you can take advantage of the SelStart and
SelText properties. As you probably know, the SelStart
property returns or sets the beginning of a selection. The
SelText returns or sets the actual selected text. If there isn't a
selection, then both properties return the insertion point. So,
to insert a new line of text in a multiline textbox, use code
similar to:
Dim strNewText As String
With Text1
strNewText = "Updated: " & Date
.SelStart = Len(.Text)
.SelText = vbNewLine & strNewText
End With
This code snippet moves the insertion point to the end of any
existing text in Text1, then inserts a new line followed by the
additional information.
For the Week of August 30th
Enabling the horizontal scrollbar in a RichTextbox
control
By default, when you add a RichTextbox control to a form,
Visual Basic sets the RightMargin property to 0. This means
that the text you enter wraps in the control. To display the
horizontal scroll bar, you must set the RightMargin property to
a value greater than the control's width. Otherwise, even if
you set the ScrollBars property to 1-rtfHorizontal, the RTB
won't display the scrollbar.
As an example, add a 3200 wide RTB to a form, then set the
RightMargin to 3300 and the ScrollBars to 1-rtfHorizontal. Run
the project and type text into the control until it extends
beyond the RTB's boundaries. When you do, Visual Basic
displays the horizontal scroll bar.
For the Week of August 23rd
Visible Cues from a Minimized Form
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 iImage As Integer
iImage = iImage + 1
If iImage > 3 Then iImage = 1
Me.Icon = ImageList1.ListImages(iImage).Picture
End Sub
For the Week of August 9th
Use the Timer control for longer than 1 minute
As you know, the Timer control provides a great way to
schedule events in a Visual Basic project. When you enable
the control, it fires off its Timer event every n milliseconds, as
determined by the TimeInterval property. However, the
TimeInterval property only accepts numbers up to 65,535, or
just over one minute. As a result, you may have wondered
how to use this control for periods longer than that. To do so,
use a form, or project level, variable to keep track of how
many times the Timer event fires. Then, in the Timer event,
re-enable the control if enough time hasn't passed. For
example, consider the code below that we attached to a
standard form.
Option Explicit
Dim iElapsedMin As Integer
Const cMax_Min As Integer = 2
Private Sub Form_Load()
Timer1.Enabled = True
iElapsedMin = 1
End Sub
Private Sub Timer1_Timer()
lblText.Visible = (iElapsedMin = cMax_Min)
Timer1.Enabled = (iElapsedMin < cMax_Min)
iElapsedMin = iElapsedMin + 1
End Sub
For a Week of August 2nd
A new Format function
Visual Basic 5 has the Format command that almost works the
same as Print. The difference is that Format shortens the
output string length if all the format characters are not used.
To work around this I wrote a Public Function called
FormatNum.
Public Function FormatNum(MyNumber As Double, FormatStr
As String) As String
' This Function returns number formatted as a string
'
with the desired minimum number of characters
' MyNumber - Use CDbl(MyNumber) in the function
'
call to prevent type mismatch error.
'
FormatNum = Format$(MyNumber, FormatStr)
If Len(FormatNum) < Len(FormatStr) Then
FormatNum = Space$(Len(FormatStr) - Len(FormatNum))
& FormatNum
End If
End Function
Use this function like this:
Print #FileNumber, FormatNum(CDbl(MyVariable), " #### ")
For the Week of June 7th
Using Server.HTMLEncode() Function
Although it is not recommended (and almost always a bad
idea) many ASP applications contain and pass connection
string information. If your ASP application was written with
ActiveX Data Objects (ADO) 1.x and it passed the ADO
ConnectionString property using HTTP POST or GET, it may
fail when switched to ADO 2.0. ADO 2.0 returns the
ConnectionString with the "Extended Properties" argument in
double-quotes. If this value is passed to an HTML property, it
will result in a truncated ConnectionString value at the first
double-quotes encountered. An example of the
ConnectionString property returned using ADO 2.0 is
displayed below:
Provider="MSDASQL.1;Data Source=Mytest;Connect Timeout=15;
Extended Properties="DSN=MyTest;DBQ=C:\MyTest.mdb;
DriverId=25;FIL=MS
Access;MaxBufferSize=512;PageTimeout=5;";
Locale Identifier=1033
The problem may be remedied by displaying the
Server.HTMLEncode() function as:
<%@ LANGUAGE="VBScript"%>
<%
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "TheConnectString.."
%%>
<form method=post action=test.asp>
<input type=hidden name=txtConnString
value="<%=Server.HTMLEncode(objConn.ConnectionString)%>">
<input type=submit value=" Submit! ">
</form>
For the Week of May 31st
Using Response.IsClientConnected Property to
Determine Browser Connection
When a browser requests an ASP page from the Web Server,
but does not wait for the entire page to be downloaded, the
server continues to process the request, wasting valuable CPU
cycles. If running Internet Information Server (IIS) 4.0, you
can use the Response.IsClientConnected property to
determine whether or not the browser is still connected to the
server.
If it is not connected to the server, processing can be stopped
to conserve CPU cycles. To do this, request an ASP page that
contains the script below and use PerfMon to monitor the CPU
cycles on the Web server. Note if you click "Stop" in the
browser, the number of CPU cycles will decrease sooner than
if the loop had continued.
<%@ LANGUAGE="VBSCRIPT" %>
<%
Function IsConnectedAfter(Seconds)
Dim StartTime
Dim PauseTime
IsConnectedAfter = True
StartTime = Now
Do While DateDiff("s", StartTime, Now) < Seconds
PauseTime = Now
Do While DateDiff("s", PauseTime, Now) < 1
'Do Nothing
Loop
Response.Write "."
If Response.IsClientConnected = False then
IsConnectedAfter = False
Exit Function
End If
Loop
End Function
%>
For the Week of May 24th
Enhancing Browser Page Load Performance
If your ASP application is experiencing browser page load
performance problems consider implementing one or both of
the following techniques.
One easy way to improve the speed performance of an ASP
page is to set the @ENABLESESSIONSTATE to False if an ASP
page does not use any session variables. To accomplish this,
insert the following line of code at the top of the ASP page.
<%@ENABLESESSIONSTATE = False%>
Page performance also may be improved by copying the
values of collection variables into local variables (as opposed
to referencing the object each time the variable value is
needed). For example, if you want to reference the
Request.ServerVariable collection to determine the users
logon id, you would use the following line of script:
Request.ServerVariables("LOGON_USER")
If you need to use this value in several places on your page, it
is much more efficient to store this value to a local variable
and then reference the local variable.
<%
Dim User
User = Request.ServerVariables("LOGON_USER")
Request.Write User
%>
For the Week of May 17th
Switching to Design View after Modifying ASP Script in
Visual InterDev
When developing an Active Server site using Visual InterDev6
you may have encountered the annoying problem of not being
able to switch the editor into Design view after you have
modified the ASP script. The Visual InterDev editor can't
switch into Design view because there is unquoted ASP script
inside of an attribute value or inside of a <select> tag. The
problem is that the Design Editor doesn't know how to handle
ASP script within certain HTML tags. Inserting the code below
into an ASP page from the Visual InterDev source Editor and
then switching to Design view will demonstrate this problem:
<SELECT>
<OPTION value="<%=Value1%>">First Option</OPTION>
</SELECT>
To get around this problem, you need to use the
Response.Write method to write out the HTML that contains
the embedded ASP. You will then be able to switch to Design
view. The HTML control however will not appear on the page.
The code below demonstrates how to accomplish this.
<SELECT>
<%
Response.Write "<OPTION value=" & Value1 & "> First
Option</OPTION>"
%>
</SELECT>
For the Week of May 10th
Parsing Using SPLIT Function
Parsing functions are one of the most commonly, over-written
string manipulation functions. Visual Basic 6.0 answered this
problem by adding a SPLIT function. The function is very easy
to use and, with only one line of code, you can parse any
string using a specific delimiter. The code looks like this:
Dim strAnimals As String
Dim iCounter As Integer
Dim arrAnimals() As String
strAnimals = "Cats,Dogs,Horses,Birds"
'-- Parse String
arrAnimals = Split(strAnimals, ",")
'-- Loop through array
For iCounter = LBound(arrAnimals) To UBound(arrAnimals)
MsgBox arrAnimals(iCounter)
Next
For the Week of May 3rd
Keep Your Background Processes Running
In Visual Basic, if you make a call to the MSGBOX function all
other background processes that you may have running
(counters, timer events, etc) are stopped until the user
acknowledges the Msgbox dialog box. This can be potentially
devastating if you write an application that runs unattended.
To overcome this problem, you must use the Windows API call
for the MessageBox function. It looks and acts the same as
the Visual Basic "msgbox" function, but does not stop the
background processes from running.
In a module, paste the following API declaration:
Declare Function MessageBox Lib "user32" Alias
"MessageBoxA" (ByVal hwnd As
Long, ByVal lpText As String, ByVal lpCaption As String,
ByVal wType As
Long) As Long
Next, on the default form add a timer control, 2 command
buttons, and a label. Then type the following code into the
form, which demonstrates the Visual Basic msgbox and API
MessageBox functions. That's all there is to it.
Private Sub Command1_Click()
MsgBox "The Timer STOPS!"
End Sub
Private Sub Command2_Click()
MessageBox Me.hwnd, "Notice the timer does not stop!",
"API Call", _
vbOKOnly + vbExclamation
End Sub
Private Sub Timer1_Timer()
Label1.Caption = Time
End Sub
For the Week of April 26th
Creating Professional Documents with Code
Have you ever wanted to create polished, professional
documents, like those created in Microsoft Word, through the
use of code? Follow these easy steps to make it happen:
First add a reference to your project for "Microsoft Word 8.0
Object Library" (MSWORD8.OLB).
Then add the following code to create an instance of Word and
add text to a new document:
Dim objWord As New Word.Application
'-- Show Microsoft Word
objWord.Visible = True
'-- Add new Document
objWord.Documents.Add
'-- Add text to Document
objWord.Selection.TypeText "Visual Basic!"
'-- Select all Text
objWord.Selection.WholeStory
'-- Change Font Size
objWord.Selection.Font.Size = 50
Set objWord = Nothing
Check out the Object Browser for more properties and
methods exposed by the Word Object.
For the Week of April 19th
Convert NULL Values to Empty Strings to Avoid Errors
One way to avoid errors from occurring when retrieving NULL
values from a recordset object is to inspect the field's value. If
it is NULL, then convert it to an empty string or zero. For
example:
If isnull(rs("Field")) then tmp="" else tmp=rs("Field")
form.textfield=tmp
An even simpler way is to use the format function, which will
convert a NULL value to an empty string automatically,
avoiding any error messages. It will look like this:
form.textfield=format(rs("Field"))
Top of Page
Friday, Feb. 26th:
Writing to the Windows NT event log
Windows applications typically write to the NT event log to
provide the user with useful information. In VB5/6, the App
object now provides methods to make writing to the event log
in Windows NT a snap:
'-- Start Event Logging
Call App.StartLogging("", vbLogToNT)
'-- Log Events to NT
Call App.LogEvent("Info", vbLogEventTypeInformation)
Call App.LogEvent("Error", vbLogEventTypeError)
Call App.LogEvent("Warning", vbLogEventTypeWarning)
Check out the Knowledge Base article App.LogEvent Only Logs
in Compiled Applications for more information.
Top of Page
Friday, Feb. 12th:
Keeping track of Visual Basic source code builds
Keeping track of source code builds in Visual Basic can be
easy, if you use the Version Numbering feature provided in
EXE creations. Click on the options button when creating an
EXE file. Then turn on the "Auto Increment" checkbox.
Versioning supports a three-segment version number: Major,
Minor and Revision. The Auto Increment feature, if selected,
will automatically increase the Revision number by one each
time you run the Make Project command for this project.
Typically, build information will go on an About form. Just add
a label called, "lblVersion" and add the following code to your
form:
lblVersion.Caption = "Version: " & App.Major & "." &
App.Minor & "."
& App.Revision
If my Major version number is 2, the Minor number is 1 and
the Revision is 12, the label will display: "Version: 2.1.12"
Top of Page
February 5, 1999
Implementing a "wait" function in Visual Basic
Here's a simple way of implementing an accurate "wait"
function in Visual Basic.
1. Add a timer called timer1 to a form. Set its Interval
property to 0 and it's enabled property to FALSE.
2. Add two labels (label1 and label2) and a command
button (command1) to the form.
3. Add the following subroutine and Timer1 event code:
4.
Public Sub Wait(seconds)
5.
6.
'-- Turn timer on
7.
Timer1.Enabled = True
8.
9.
'-- Set Timer Interval
10.
Me.Timer1.Interval = 1000 * seconds
11.
While Me.Timer1.Interval > 0
12.
13.
DoEvents
Wend
14.
15.
'-- Turn timer off
16.
Timer1.Enabled = False
17.
End Sub
18.
19.
Private Sub Timer1_Timer()
20.
21.
Timer1.Interval = 0
End Sub
That's it! Use the Wait function anywhere a delay is required,
for example:
Private Sub Command1_Click()
Label1.Caption = Now
Wait (5)
Label2.Caption = Now
End Sub
Top of Page
January 29, 1999
Create templates from existing forms
Here's a way for you to create a template from an existing
form so you can use it to design future forms. Once you've
created the 'perfect' form, place it in the ..\Template\Forms\
subdirectory. Now, the next time you want to add a new form
to your project, you'll see that the newly created form is in the
list of available form templates! Just select it and you're on
your way. This tip also applies to modules, classes, etc.
Top of Page
January 4, 1999
Nothing to declare?
When you use the Windows API, you should never need to
write your own Declare statement. The API Text Viewer utility
loads in a text file (WIN31API.TXT for 16-bit, and
WIN32API.TXT for 32-bit) and lets you copy declares, global
constants, and user-defined types. You can also convert the
text file to an Access database for faster searching. Handy,
eh?
Top of Page
November 16, 1998
Figuring out the current screen resolution
You can use the following small piece of code to detect the
current screen resolution and then act on the information - for
instance, by resizing form objects to suit the user's resolution.
Dim x,y As Integer
x = Screen.Width / 15
y = Screen.Height / 15
If x = 640 And y = 480 Then MsgBox ("640 * 480")
If x = 800 And y = 600 Then MsgBox ("800 * 600")
If x = 1024 And y = 768 Then MsgBox ("1024 * 768")
Top of Page
November 09, 1998
Finding the last day of the month
In many industries (particularly in the insurance industry), it's
important to know the last day of the month. To find the last
day of a given month, add a text box and a command button
to a form. Enter the following code in the command button:
Dim TEMP2 As Date
Dim nLastDay As Integer
TEMP2 = InputBox$("Please Enter A Date", "LastDay")
nLastDay = DatePart("d", DateAdd("M", 1, TEMP2 DatePart("d", TEMP2)))
Text1.Text = nLastDay
When you run the application and click the button, you'll be
prompted for a date. Then, the program will display the last
day of that month of any year.
Top of Page
August 31, 1998
GETting the contents of a file
submitted by Pritesh
TransCapacity LP; spritesh@hotmail.com
To read a complete file in Visual Basic, the normal procedure
is to read the contents of the file line by line and accumulate it
into a string. Instead, you can use the GET function to read
the file with a single call. Doing so simplifies and speeds up
the process of reading a file.
You can use the following function:
Dim Handle As Integer
Dim FileString As String
Handle = FreeFile
Open "C:\TEMP\TST.TXT" For Binary As #Handle
FileString = Space(FileLen("C:\TEMP\TST.TXT"))
Get #Handle, ,FileString
Close #Handle
This code involves a single call to return the contents of the
file.
Top of Page
August 24, 1998
Help with Shell
submitted by Brad Gile
bgile@amfam.com
Suppose you have a DOS program, Dosapp.exe. This program
produces an output file that will subsequently be processed,
and you want to do this N times. The code might look like
this:
for Trial = 1 to N
x=shell("Dosapp.exe",vbHide)
Process the output
Next Trial
The problem is, the code after the Shell may be executed
before the Shelled Dosapp.exe has created the file. There are
complicated ways of solving this, including API calls, but
here's a simple solution: the FileLen function. If the file to be
processed is x$, you can just insert a few lines of code:
for Trial = 1 to N
Open x$ for output as 1
Close 1
' This sets file length equal to zero
x=shell("Dosapp.exe",vbHide)
Do While FileLen(x$) = 0
DoEvents
' Halt further execution until x$ is created and
closed
Loop
' Process the output to add to a new file
Next Trial
You may want to do other things such as using Timer to
prevent an infinite Do Loop, but this is the main idea.
FileLen() works because even if x$ is open and has data in it,
FileLen(x$) = 0. Thus you're assured that the process code
won't execute until x$ is fully created.
Top of Page
August 17, 1998
Watch your window state
submitted by Rick Michelhaugh
3m8@ornl.gov
My application saves the window location and size, so it will
open the next time at the same screen location. This
technique is great and pleases customers. But after several
months, the program wouldn't start right -- it would die with
an 'overflow error'. We tried every possible test, and could
only determined that something in the INI file had become
corrupted. Finally, we found that the window's Top, Left,
Width, and Height values were incorrect. When the program
started and read these wrong numbers, the 'overflow error'
was the result.
As it turned out, the numbers were being thrown off when the
user minimized the window and exited Windows with it
minimized. As the program closes, it saves the position values
of the minimized state -- which messes up the values. To fix
the problem, we added some code to check the windowstate.
If it's vbMinimized, the program skips the code that saves the
window position.
Top of Page
August 10, 1998
Writing to and reading from INI files
submitted by David Dommisse
Dommisse@hotmail.com
Here's an example that will write to and read from a INI file.
You can use a file named TEST.INI that looks like this:
[MyApp]
Key1= TestString
Put the following code in the declaration section of a module:
View Source
Now, use the following code to read from the INI file:
View Source
The key's value will be in retStr = TestString. The following
code will write to the INI file:
View Source
After you write to the INI file, its contents will look like this:
[MyApp]
Key1=TestString
Key2=My Test
Top of Page
August 3, 1998
Tracking down Resume Next
submitted by Bill Shadish
Fundamental Objects, Inc; bills@fo.com
This tip is extremely simple. But try it, and see if it helps you
some time in the future.
Maybe you've inherited a large chunk of code from that
developer who's smiling on the way out the door. Or, perhaps
you're getting ready to ship that version 1.0 application to 100
users, try this. In any case, take a minute to search all of the
code for the string
On Error Resume Next
In fact, try this even if you don't want to ship your code to
100 users -- or especially if you have code that seems to fail
"for no reason." You might be surprised at what that ol'
Resume Next is hiding.
Top of Page
July 27, 1998
Labeling your forms
submitted by Bill Shadish
Fundamental Objects, Inc; bills@fo.com
Do you have a ton of screens in your application? Do you also
have plenty of users who want to "help you" by pointing out
buttons that are one twip out of place? Sometimes it's hard to
know what screen users are talking about when they're trying
to communicate a problem -- particularly if they're in a
different location than you.
To reduce the pain of this process, I add a label (called
lblHeader) to the top of each GUI window, nominally to hold
start-up information for users when they first open the
window. You can also use this label to hold the name of the
window the user is looking at, by using the following code:
Private Sub Form_Load()
SetupScreen me
End Sub
Public SetupScreen (frm as Form)
' Do other set-up stuff here (fonts, colors).
HookInFormName frm
End Sub
Public Sub HookInFormName(frm As Form)
' The Resume Next on Error allows forms that do not
use a standard
' header label to get past this.
On Error Resume Next
frm.lblHeader.Caption = "(" & frm.Name & ") " &
frm.lblHeader.Caption
End Sub
Note that if you don't want to use a label, that you can also
use code like
frm.print frm.name
to print to the back of the window itself.
Top of Page
For the Week of July 6, 1998
Opening a browser to your homepage
submitted by Dan Newsome
D&D Information Professionals, newsomed@earthlink.net
You can use code like the following to open a browser to your
homepage. Modify filenames, paths, and URLs as necessary to
match the values on your system.
Dim FileName As String, Dummy As String
Dim BrowserExec As String * 255
Dim RetVal As Long
Dim FileNumber As Integer
Const SW_SHOWNORMAL = 1 ' Restores Window if Minimized or
Declare Function ShellExecute Lib "shell32.dll" Alias
"ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal
lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String,
_
ByVal nShowCmd As Long) As Long
Declare Function FindExecutable Lib "shell32.dll" Alias
"FindExecutableA" _
(ByVal lpFile As String, ByVal lpDirectory As String,
ByVal lpResult As _
String) As Long
'<Code> ---------
BrowserExec = Space(255)
FileName = "C:\temphtm.HTM"
FileNumber = FreeFile()
' Get unused file number
Open FileName For Output As #FileNumber
HTML file
Write #FileNumber, "
' Create temp
<\HTML>" ' Output text
Close #FileNumber ' Close file
' Then find the application associated with it.
RetVal = FindExecutable(FileName, Dummy,
BrowserExec)
BrowserExec = Trim$(BrowserExec)
' If an application is found, launch it!
If RetVal <= 32 Or IsEmpty(BrowserExec) Then ' Error
Msgbox "Could not find a browser"
Else
RetVal = ShellExecute(frmMain.hwnd, "open",
BrowserExec, _
"www.myurl.com", Dummy, SW_SHOWNORMAL)
If RetVal <= 32 Then
' Error
Msgbox "Web Page not Opened"
End If
End If
Kill FileName ' delete temp HTML file
Top of Page
For the Week of June 29, 1998
Creating a incrementing number box
submitted by Bryan Shoemaker
www.shadow.net/~fubar
You can't increment a vertical scroll bar's value -- a fact that
can become annoying. For example, start a new project and
place a text box and a vertical scroll bar on the form. Place
the vertical scroll bar to the right of the text box and assign
their Height and Top properties the same values. Assign the
vertical scroll bar a Min property value of 1 and a Max value of
10. Place the following code in the vertical scroll bar's Change
event:
Text1.Text = VScroll1.Value
Now press [F5] to run the project. Notice that if you click on
the bottom arrow of the vertical scroll bar, the value
increases; if you click on the top arrow, the value decreases.
From my perspective, it should be the other way around.
To correct this, change the values of the Max and Min
properties to negative values. For example, end the program
and return to the design environment. Change the vertical
scroll bar's Max value to -1 and its Min value to -10. In its
Change event, replace the line you entered earlier with the
following:
Text1.Text = Abs(Vscroll1.Value)
Now press [F5] to run the project. When you click on the top
arrow of the vertical scroll bar, the value now increases.
Adjust the Height properties of the text box and the scroll bar
so you can't see the position indicator, and your number box
is ready to go.
Top of Page
For the Week of June 22, 1998
Measuring a text extent
submitted by Nenad Cus Babic
Nenad@computer.org
It's very simple to determine the extent of a string in Visual
Basic. You can do so with WinAPI functions, but there's an
easier way: Use the AutoSize property of a Label component.
First, insert a label on a form (labMeasure) and set its
AutoSize property to True and Visible property to False. Then
write this simple routine:
Private Function TextExtent(txt as String) as Integer
labMeasure.Caption = txt
TextExtent = labMeasure.Width
End Function
When you want to find out the extent of some text, simply call
this function with the string as a parameter.
In my case it turned out that the measure was too short. I
just added some blanks to the string. For example:
Private Function TextExtent(txt As String) As Integer
labMeasure.Caption = "
" & txt
TextExtent = labMeasure.Width
End Function
Top of Page
For the Week of June 15, 1998
Importing Registry settings
submitted by Dan Newsome
D&D Information Professionals, newsomed@earthlink.net
You can use just a few lines of code to import Registry
settings. If you have an application called myapp.exe and a
Registry file called myapp.reg, the following code will put
those settings into the Registry without bothering the user.
Dim strFile As String
strFile = App.Path & "\" & opts.AppExeName & ".reg"
If Len(Dir$(strFile)) > 1 Then
lngRet = Shell("Regedit.exe /s " & strFile,
vbNormalFocus)
End If
Top of Page
For the Week of June 01, 1998
Use FreeFile to Prevent File Open Conflicts
Submitted by markus@bactive.com
Both Access and Visual Basic let you hard code the file
numbers when using the File Open statement. For example:
Open "myfile.txt" for Append as #1
Print #1,"a line of text"
Close #1
The problem with this method of coding is that you never
know which file numbers may be in use somewhere else in
your program. If you attempt to use a file number already
occupied, you'll get a file error. To prevent this problem, you
should always use the FreeFile function. This function will
return the next available file number for your use. For
example:
IntFile=FreeFile()
Open "myfile.txt" for Append as #intFile
Print #intFile,"a line of text"
Close #intFile
Top of Page
For the Week of May 25, 1998
Confirm Screen Resolution
Submitted by Nicholas L. Otley, nicholaso@kalamzoo.co.uk;
www.kalamazoo.co.uk
Here's a great way to stop the user from running your
application in the wrong screen resolution. First, create a
function called CheckRez:
Public Function CheckRez(pixelWidth As Long, pixelHeight
As Long) As Boolean
'
Dim lngTwipsX As Long
Dim lngTwipsY As Long
'
' convert pixels to twips
lngTwipsX = pixelWidth * 15
lngTwipsY = pixelHeight * 15
'
' check against current settings
If lngTwipsX <> Screen.Width Then
CheckRez = False
Else
If lngTwipsY <> Screen.Height Then
CheckRez = False
Else
CheckRez = True
End If
End If
'
End Function
Next, run the following code at the start of the program:
If CheckRez(640, 480) = False Then
MsgBox "Incorrect screen size!"
Else
MsgBox "Screen Resolution Matches!"
End If
Top of Page
For the Week of May 18, 1998
Quick Text Select On GotFocus
Submitted by scott@beacon-inc.com
When working with data entry controls, the current value in
the control often needs to be selected when the control
received focus. This allows the user to immediately begin
typing over any previous value. Here's a quick subroutine to
do just that:
Public Sub FocusMe(ctlName As Control)
'
With ctlName
.SelStart = 0
.SelLength = Len(ctlName)
End With
'
End Sub
Now add a call to this subroutine in the GotFocus event of the
input controls:
Private Sub txtFocusMe_GotFocus()
Call FocusMe(txtFocusMe)
End Sub
Top of Page
For the Week of May 11, 1998
Take Advantage of Built-in OLE Drag and Drop
Submitted by Michael C. Amundsen,
mike_tips@amundsen.com, http://www.amundsen.com
To add fully functional drag and drop to your forms, all you
need to do is set the OLEDragMode property and
OLEDropMode property of the input controls to "Automatic."
This works across forms and even across applications on the
same workstation. To test this, add two text boxes to a form.
Use the Property Window to set the OLEDragMode and
OLEDropMode properties to "Automatic." Now run the app and
enter text in one text box and drag and drop it into the other
text box.
Hint: Some controls only support OLEDrag. A few others do
not support OLEDrag or OLEDrop. To determine what a control
supports, check for the OLEDragMode and OLEDropMode
properties. If their missing the control does not support
OLEDrag and/or OLEDrop.
Top of Page
For the Week of May 04, 1998
Use ParamArray to Accept an Arbitrary Number of
Parameters
Submitted by Michael C. Amundsen,
mike_tips@amundsen.com, http://www.amundsen.com
You can use the ParamArray keyword in the declaration line of
a method to create a subroutine or function that accepts an
arbitrary number of parameters at runtime. For example, you
can create a method that will fill a list box with some number
of items even if you do not know the number of items you will
be sent. Add the method below to a form:
Public Sub FillList(ListControl As ListBox, ParamArray
Items())
'
Dim i As Variant
'
With ListControl
.Clear
For Each i In Items
.AddItem i
Next
End With
'
End Sub
Note that the ParamArray keyword comes BEFORE the
parameter in the declaration line. Now add a list box to your
form and a command button. Add the code below in the
"Click" event of the command button.
Private Sub Command1_Click()
'
FillList List1, "TiffanyT", "MikeS", "RochesterNY"
'
End Sub
Top of Page
For the Week of April 27, 1998
Use FileDSNs to ease ODBC Installs
Submitted by Michael C. Amundsen,
mike_tips@amundsen.com, http://www.amundsen.com
If you're using an ODBC connection to your database, you can
ease the process of installing the application on workstations
by using the FileDSN (data source name) instead of the morecommon UserDSN. You define your ODBC connection as you
normally would with UserDSNs. However, the resulting
definition is not stored in the workstation registry. Instead it
gets stored in a text file with the name of the DSN followed by
".dsn" (i.e. "MyFileDSN.dsn"). The default folder for all
FileDSNs is "c:\program files\common files\Odbc\data
sources". Now, when you want to install the Visual Basic
application that uses the FileDSN, all you need to do is add
the FileDSN to the Install package and run the install as usual.
No more setting up DSNs manually!
NOTE: FileDSNs are available with ODBC 3.0 and higher.
Top of Page
For the Week of April 20, 1998
Increase Your RAD-ness by Creating Your Own VB5
Templates
Submitted by Michael C. Amundsen,
mike_tips@amundsen.com, http://www.amundsen.com
You can create your own Visual Basic Templates quickly and
easily. If you find that you are adding the same routines to
your forms, classes, BAS modules, etc. you can build generic
versions and place them in the Templates folder tree of VB5.
By placing the coding module (frm, bas.cls, etc.) in the proper
subfolder of the Templates folder, you'll see the new item
appear whenever you select the Add... dialog box. You can
add as many controls, library references, and lines of code as
you wish to the templates.
CAUTION: If you uninstall VB5, you may loose your Templates
folder and all its contents. Be sure to keep a secured copy of
all your template files in a safe location.
Top of Page
For the Week of April 06, 1998
Add Dithered Backgrounds to your Visual Basic Forms
By: Barron Anderson, Micron Electronics, Inc.
Ever wonder how the SETUP.EXE screen gets its cool shaded
background coloring? This color shading is called dithering,
and you can easily incorporate it into your forms. Add the
following routine to a form:
View Source
Now, add to the Form_Activate event the line
Dither ME
This version creates a fading blue background by adjusting the
blue value in the RGB function. (RGB stands for Red-GreenBlue.) You can create a fading red background by changing
the RGB call to
RGB(255 - intLoop, 0, 0).
Top of Page
For the Week of March 30, 1998
Dragging items from a list to another one
By Bassam Alkharashi, bkhrashi@kacst.edu.sa
Here's a way that you can let users drag items from one list
and drop them in another one. Create two lists
(lstDraggedItems, lstDroppedItems) and a text box (txtItem)
in a form (frmTip).
Put the following code in the load event of your form.
Private Sub Form_Load()
' Set the visible property of txtItem to false
txtItem.Visible = False
'Add items to list1 (lstDraggedItems)
lstDraggedItems.AddItem "Apple"
lstDraggedItems.AddItem "Orange"
lstDraggedItems.AddItem "Grape"
lstDraggedItems.AddItem "Banana"
lstDraggedItems.AddItem "Lemon"
'
End Sub
In the mouseDown event of the list lstDraggedItems put the
following code:
View Source
In the dragDrop event of the list lstDroppedItems put the
following code:
View Source
Now you can drag items from lstDraggedItems and drop them
in LstDroppedItems.
Note that you cannot drag from the second list to the first.
Also, the dragged item remains in the first list. You'll have to
address those limitations yourself.
Top of Page
For the Week of March 23, 1998
Creating a new context menu in editable controls
By Antonio Almeida, future.systems@mail.telepac.pt
This routine will permit you to replace the original context
menu with your private context menu in an editable control.
Add the following code to your form or to a BAS module:
View Source
Next, use the Visual Basic Menu Editor and the table below to
create a simple menu.
Caption
Name
Visible
Context Menu
mnuContext
NO
...First Item
mnuContext1
...Second Item
mnuContext2
Note that the last two items in the menu are indented (...)
one level and that only the first item in the list ("Context
Menu") has the Visible property set to NO.
Now add a text box to your form and enter the code below in
the MouseDown event of the text box.
View Source
Note: If you just want to kill the system context menu, just
comment out the line:
FormName.PopupMenu MenuName
in the OpenContextMenu routine.
Top of Page
For the Week of March 16, 1998
Quick Custom Dialogs for DBGrid Cells
By Mike Amundsen, mike@amundsen.com,
http://www.amundsen.com
It's easy to add custom input dialogs to all the cells in the
Microsoft Data Bound Grid control.
First, add a DBGrid control and Data control to your form.
Next, set the DatabaseName and RecordSource properties of
the data control to a valid database and table ("biblio.mdb"
and "Publishers" for example). Then set the DataSource
property of the DBGrid control to Data1 (the data control).
Now add the following code to your form.
View Source
Now whenever you attempt to edit any cell in the DBGrid,
you'll see the InputBox prompt you for input. You can replace
the InputBox with any other custom dialog you wish to build.
Top of Page
For the Week of March 9, 1998
Using the Alias Option to Prevent API Crashes
By Mike Amundsen mike@amundsen.com,
http://www.amundsen.com
A number of Windows APIs have parameters that can be more
than one data type. For example, the WinHelp API call can
accept the last parameter as a Long or String data type
depending on the service requested.
Visual Basic allows you to declare this data type as "Any" in
the API call, but this can lead to type mismatch errors or even
system crashes if the value is not the proper form.
You can prevent the errors and improve the run-time type
checking by declaring multiple versions of the same API
function in your program. By adding a function declaration for
each possible parameter type, you can continue to use strong
data type checking.
To illustrate this technique, add the following APIs and
constants to a Visual Basic form. Notice that the two API
declarations differ only in their initial name ("WinHelp" and
"WinHelpSearch") and the type declaration of the last
parameter ("dwData as Long" and "dwData as String").
View Source
Now add two command buttons to your form (cmdHelpAbout
and cmdHelpSearch) and place the following code behind the
buttons. Be sure to edit the location of the help file to match
your installation of Visual Basic.
Private Sub cmdHelpAbout_Click()
'
WinHelp Me.hwnd, HelpFile, HELP_HELPONHELP, &H0
'
End Sub
Private Sub cmdHelpSearch_Click()
'
WinHelpSearch Me.hwnd, HelpFile, HELP_PARTIALKEY,
"option"
'
End Sub
When you press on the HelpAbout button, you'll see help
about using the help system. When you press on the
HelpSearch button, you'll see a list of help entries on the
"option" topic.
Top of Page
For the Week of March 2, 1998
Increment and decrement dates with the [+] and [-]
keys
By Mike Coleman, Mike.Coleman@anixter.com
If you've ever used Quicken, you've probably noticed a handy
little feature in that program's date fields. You can press the
[+] key to increment one day, [-] to decrement one day,
[PgUp] to increment one month, and [PgDn] to decrement one
month. In this tip, we'll show you how to emulate this
behavior with Visual Basic.
First, insert a text box on a form (txtDate). Set its text
property to "" and its Locked property to TRUE.
Now place the following code in the KeyDown event:
View Source
The one nasty thing about this is that if you have characters
that are not the characters usually in a date (i.e., 1-9,
Monday, Tuesday, or /) you get errors in the format
command. To overcome this, I set the Locked property to
True. This way, the user can't actually type a character in the
field, but the KeyDown event still fires.
Top of Page
For the Week of Febuary 23, 1998
Creating Win32 region windows
By AlMoataz B. Ahmed, AlMoataz_m@hotmail.com
The Win32 API includes a really amazing feature called region
windows. A window under Win32 no longer has to be
rectangular! In fact, it can be any shape that may be
constructed using Win32 region functions. Using the
SetWindowRgn Win32 function from within Visual Basic is so
simple, but the results are unbelievable. The following
example shows a Visual Basic form that is NOT rectangular.
Enjoy!
' This goes into the General Declarations section:
Private Declare Function CreateEllipticRgn Lib "gdi32" _
(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, _
ByVal Y2 As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" _
(ByVal hWnd As Long, ByVal hRgn As Long, _
ByVal bRedraw As Boolean) As Long
Private Sub Form_Load()
Show 'The form!
SetWindowRgn hWnd, _
CreateEllipticRgn(0, 0, 300, 200), _
True
End Sub
Top of Page
For the Week of Febuary 16, 1998
Manipulate your controls from the keyboard
By Narayana Vyas Kondreddi, vyas@aditi.com,
http://members.tripod.com/~vyaskn/index.html
If you're not comfortable using your mouse--or can't achieve
the precise results you'd like--these tips will come in handy.
First, you can resize controls at design time by using the
[Shift] and arrow keys, as follows:
SHIFT + RIGHT ARROW increases the width of the control
SHIFT + LEFT ARROW decreases the width of the control
SHIFT + DOWN ARROW increases the height of the
control
SHIFT + UP ARROW decreases the height of the control
Note: The target control must have focus, so click on the
control before manipulating it from the keyboard.
Second, by using the [Control] key and the arrow keys, you
can move your controls at design time, as follows:
CONTROL + RIGHT ARROW to move the control to the right
CONTROL + LEFT ARROW to move the control to the left
CONTROL + DOWN ARROW to move the control downwards
CONTROL + UP ARROW to move the control upwards
If you select more than one control (by clicking on the first
and shift-clicking on the others), the above procedures will
affect all the selected controls.
Top of Page
For the Week of Febuary 9, 1998
Simple file checking from anywhere
By Matthew Kent, mace@pacificcoast.net
To keep my applications running smoothly, I often need to
check that certain files exist. So, I've written a simple routine
to make sure they do. Here it is:
Public Sub VerifyFile(FileName As String)
'
On Error Resume Next
'Open a specified existing file
Open FileName For Input As #1
'Error handler generates error message with file and
exits the routine
If Err Then
MsgBox ("The file " & FileName & " cannot be
found.")
Exit Sub
End If
Close #1
'
End Sub
Now add a button to your form and place the code below
behind the "Click" event.
Private Sub cmdVerify_Click()
'
Call VerifyFile("MyFile.txt")
'
End Sub
Top of Page
For the Week of 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 Visual Basic 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
Top of Page
Last Updated: 9/18/00
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.