tr                                                      


Bookmark Site 

 

Welcome to TechRiz 

Where tech enthusiasts come for the latest tech news, Free downloads, free tutorials, articles and how to's.


Description:  This is the TechRiz Free Tutorials page. Visit every day to stay informed about the latest tech news, from security alerts to Hardware and software updates. Enjoy your stay.



Week 4 – Visual Basic Tutorial 

Assigning and returning arrays in Visual Basic 6  

Visual Basic 6 adds two important features to arrays. First, you can perform assignments between arrays. Second, you can write procedures that return arrays. You can assign arrays only of the same type and only if the target is a dynamic array. (The latter condition is necessary because Visual Basic might need to resize the target array.)

ReDim a(10, 10) As Integer
Dim b() As Integer
' Fill the a array with data (omitted).
b() = a() ' This works!

It's no surprise that native assignment commands are always faster than the corresponding For…Next loops that copy one item at a time. The actual increment in speed heavily depends on the data type of the arrays and can vary from 20 percent to 10 times faster. A native assignment between arrays also works if the source array is held in a Variant. Under Visual Basic 4 and 5, you could store an array in a Variant, but you couldn't do the opposite—that is, retrieve an array stored in a Variant variable and store it back in an array of a specific type. This flaw has been fixed in Visual Basic 6:

Dim v As Variant, s(100) As String, t() As String
' Fill the s() array (omitted).
v = s() ' Assign to a Variant.
t() = v ' Assign from a Variant to a dynamic string array.

You often use the capacity to assign arrays to build functions that return arrays. Notice that pair of brackets at the end of the first line in the following procedure:

Function InitArray(first As Long, Last As Long) As Long()
ReDim result(first To Last) As Long
Dim i As Long
For i = first To Last
result(i) = i
Next
InitArray = result
End Function

The new capability of returning arrays lets you write highly versatile array routines. Visual Basic 6 itself includes a few new string functions—namely Join, Split, and Filter—that rely on it. (You'll find more about these new string functions in Chapter 5). Here are two examples of what you can do with this intriguing feature:

' Returns a portion of a Long array
' Note: fails if FIRST or LAST are not valid
Function SubArray(arr() As Long, first As Long, last As Long, _
newFirstIndex As Long) As Long()
Dim i As Long
ReDim result(newFirstIndex To last _ first + newFirstIndex) As Long
For i = first To last
result(newFirstIndex + i - first) = arr(i)
Next
SubArray = result
End Function

' Returns an array with all the selected items in a ListBox
Function SelectedListItems(lst As ListBox) As String()
Dim i As Long, j As Long
ReDim result(0 To lst.SelCount) As String
For i = 0 To lst.ListCount - 1
If lst.Selected(i) Then
j = j + 1
result(j) = lst.List(i)
End If
Next
SelectedListItems = result
End Function

Byte Arrays in VB6 (Visual Basic 6) 

Byte arrays are somewhat special because Visual Basic lets you directly assign strings to them. In this case, Visual Basic performs a direct memory copy of the contents of the string. Because all Visual Basic 5 and 6 strings are Unicode strings (two bytes per character), the target array is redimensioned to account for the actual string length in bytes (which you can determine using the LenB function). If the string contains only characters whose code is in the range 0 through 255 (the case if you work with Latin alphabets), every other byte in the array will be 0:

Dim b() As Byte, Text As String
Text = "123"
b() = Text ' Now b() contains six items: 49 0 50 0 51 0

It's also possible to perform the opposite operation:

Text = b()

This special treatment reserved for Byte arrays is meant to ease the conversion from old Visual Basic 3 applications that use strings to hold binary data, as I explained in "The Byte Data Type" section, earlier in this chapter. You can exploit this feature to create blindingly fast string routines when you have to process each individual character in a string. For example, see how quickly you can count all the spaces in a string:

' NOTE: this function might not work with non-Latin alphabets.
Function CountSpaces(Text As String) As Long
Dim b() As Byte, i As Long
b() = Text
For i = 0 To UBound(b) Step 2
' Consider only even-numbered items.
' Save time and code using the function name as a local variable.
If b(i) = 32 Then CountSpaces = CountSpaces + 1
Next
End Function

The preceding routine is about three times faster than a regular routine, which uses Asc and Mid$ functions to process all the characters in the argument, and even faster if you turn on the Remove Array Bounds Check compiler optimization. The only drawback of this technique is that it isn't Unicode-friendly because it considers only the least significant byte in each 2-byte character. If you plan to convert your application to some language that relies on Unicode—Japanese, for example—you should stay clear of this optimization technique

Inserting and deleting items using Arrays- Visual Basic 6 

Some of the most common operations you perform on arrays are inserting and deleting items, shifting all the remaining elements toward higher indices to make room or toward lower indices to fill the "hole" a deletion has left. You usually do this with a For…Next loop, and you can even write generic array procedures that work with any type of array (with the usual restrictions about arrays of UDTs and fixed-length strings that can't be passed to a Variant parameter):

Sub InsertArrayItem(arr As Variant, index As Long, newValue As Variant)
Dim i As Long
For i = UBound(arr) - 1 To index Step -1
arr(i + 1) = arr(i)
Next
arr(index) = newValue
End Sub

Sub DeleteArrayItem(arr As Variant, index As Long)
Dim i As Long
For i = index To UBound(arr) - 1
arr(i) = arr(i + 1)
Next
' VB will convert this to 0 or to an empty string.
arr(UBound(arr)) = Empty
End Sub

If your application works intensively with arrays, you might find that an approach based on For…Next loops is too slow. In some cases, you can considerably speed up these operations by using the RtlMoveMemory API function, which many Visual Basic programmers know under its popular alias name, CopyMemory.1 This function lets you move a block of bytes from one memory address to another memory address and works correctly even if the two areas partially overlap. Here's the code that inserts a new item in an array of Longs:

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(dest As Any, source As Any, ByVal numBytes As Long)

Sub InsertArrayItemLong(arr() As Long, index As Long, newValue As Long)
' We let VB evaluate the size of each item using LenB().
If index < UBound(arr) Then
CopyMemory arr(index + 1), arr(index), _
(UBound(arr) _ index) * LenB(arr(index))
End If
arr(index) = newValue
End Sub

Sub DeleteArrayItemLong(arr() As Long, index As Long)
If index < UBound(arr) Then
CopyMemory arr(index), arr(index + 1), _
(UBound(arr) _ index) * LenB(arr(index))
End If
arr(index) = Empty
End Sub

IMPORTANT NOTE: The prerequisite for using the CopyMemory API function is that data must be stored in contiguous memory locations, so you absolutely can't use it to insert or remove elements in String and Object arrays, nor in arrays of UDTs that contain conventional strings, object references, or dynamic arrays. (Fixed-length strings and static arrays in UDTs are OK, though.)

Note that while you can't use the preceding routines for arrays other than Long arrays, the statements in the procedure body can be recycled for another data type without any change, thanks to the use of the LenB function. Therefore, you can derive new array functions that work for other data types by simply modifying the procedure's name and its parameter list. For example, you can create a new function that deletes an item in a Double array by editing just the first line of code (shown in boldface):

Sub DeleteArrayItemDouble(arr() As Double, index As Long)
' All the other statements here are the same as in DeleteArrayItemLong
' ...
End Sub

Sorting Data using Arrays - Visual Basic 6 

Sorting is an operation that you often perform on arrays. As you probably know, there are dozens of different sort algorithms, each one with its strengths and weaknesses. I found that the Shell Sort algorithm works well in most cases, and I've prepared a generic routine that sorts any one-dimensional array of a data type compatible with the Variant type, either in ascending or descending order:

Sub ShellSortAny(arr As Variant, numEls As Long, descending As Boolean)
Dim index As Long, index2 As Long, firstItem As Long
Dim distance As Long, value As Variant
' Exit if it is not an array.
If VarType(arr) < vbArray Then Exit Sub
firstItem = LBound(arr)
' Find the best value for distance.
Do
distance = distance * 3 + 1
Loop Until distance > numEls
' Sort the array.
Do
distance = distance \ 3
For index = distance + firstItem To numEls + firstItem - 1
value = arr(index)
index2 = index
Do While (arr(index2 - distance) > value) Xor descending
arr(index2) = arr(index2 - distance)
index2 = index2 - distance
If index2 - distance < firstItem Then Exit Do
Loop
arr(index2) = value
Next
Loop Until distance = 1
End Sub

Arrays of arrays in VB6 (Visual Basic 6) 

While you can create two-dimensional arrays in Visual Basic, their structure isn't really flexible for at least two reasons: All rows in the array must have the same number of elements, and you can use ReDim Preserve to change the number of columns but you can't add new rows. The first point is especially important because it often leads you to declare an array that's far too large for your needs, thus allocating a lot of memory that in most cases remains largely unused. You can solve both problems using a structure known as an array of arrays. 

The technique is conceptually simple: Since you can store an array in a Variant variable, you can build an array of Variants, where each item holds an array. Each subarray—a row of this pseudo-array—can hold a different number of elements, and you don't need to use more memory than is strictly necessary. 

 

aavb

Here's an example, based on an imaginary PIM (Personal Information Manager) program. In this program, you need to keep track of a list of appointments for each day of the year. The simplest solution would be to use an array in which each row corresponds to a day in the year and each column to a possible appointment. (For the sake of simplicity, let's assume that each appointment's data can be held in a string.) 

ReDim apps(1 To 366, 1 To MAX_APPOINTMENTS) As String 

Of course, you now have the problem of setting a reasonable value for the MAX_APPOINTMENTS symbolic constant. It should be high enough to account for all possible appointments in a day but not too high because you might be wasting a lot of memory without any real reason. Let's see how the array of arrays technique can help us save memory without posing any artificial limit to your application: 

' A module-level variable
Dim apps(1 To 366) As Variant 

' Add an appointment for a given day.
Sub AddNewAppointment(day As Integer, description As String)
Dim arr As Variant
If IsEmpty(apps(day)) Then
' This is the first appointment for this day.
apps(day) = Array(description)
Else
' Add the appointment to those already scheduled.
arr = apps(day)
ReDim Preserve arr(0 To UBound(arr) + 1) As Variant
arr(UBound(arr)) = description
apps(day) = arr
End If
End Sub 

' Extract all the appointments for a given day.
Sub ListAppointments(day As Integer, lst As ListBox)
Dim i As Long
For i = 0 To UBound(apps(1))
lst.AddItem apps(1)(i)
Next
End Sub 

In this example, I kept the code as simple as possible and used an array of Variant arrays. You could save even more memory if each row of this array were built using an array of a more specific data type (String, in this case). Note the special syntax used to address an item in an array of arrays:  

' Change the description for the Nth appointment.
apps(day)(n) = newDescription 

Nothing keeps you from extending this concept further, introducing an array of arrays of arrays, and so on. If you're dealing with arrays in which each row can vary considerably in length, this approach is going to save you a lot of memory and, in most cases, improve your overall performance too. A key feature of an array of arrays is that you can process entire rows of your pseudo-array as if they were single entities. For example, you can swap them, replace them, add and delete them, and so on. 

' Move the January 1st appointments to January 2nd.
apps(2) = apps(1)
apps(1) = Empty 

Finally, an important advantage of this technique is that you can add new rows without losing the current contents of the array. (Remember that you can use ReDim Preserve on regular arrays only to modify the number of columns, not the number of rows.)  

' Extend the appointment book for another nonleap year.
ReDim Preserve apps(1 to UBound(apps) + 365) As Variant 

User-Defined Data Types 

Variables of different data types when combined as a single variable to hold several related informations is called a User-Defined data type.  

A Type statement is used to define a user-defined type in the General declaration section of a form or module. User-defined data types can only be private in form while in standard modules can be public or private. An example for a user defined data type to hold the product details is as given below. 

Private Type ProductDetails
ProdID as String
ProdName as String
Price as Currency
End Type 

The user defined data type can be declared with a variable using the Dim statement as in any other variable declaration statement. An array of these user-defined data types can also be declared. An example to consolidate these two features is given below. 

Dim ElectronicGoods as ProductDetails ' One Record
Dim ElectronicGoods(10) as ProductDetails ' An array of 11 records 

A User-Defined data type can be referenced in an application by using the variable name in the procedure along with the item name in the Type block. Say, for example if the text property of a TextBox namely text1 is to be assigned the name of the electronic good, the statement can be written as given below. 

Text1.Text = ElectronicGoods.ProdName 

If the same is implemented as an array, then the statement becomes 

Text1.Text = ElectronicGoods(i).ProdName 

User-defined data types can also be passed to procedures to allow many related items as one argument. 

Sub ProdData( ElectronicGoods as ProductDetails)
Text1.Text = ElectronicGoods.ProdName
Text1.Text = ElectronicGoods.Price
End Sub 

Constants, Data Type Conversion, Visual Basic Built-in Functions 

Constants 

Constants are named storage locations in memory, the value of which does not change during program Execution. They remain the same throughout the program execution. When the user wants to use a value that never changes, a constant can be declared and created. The Const statement is used to create a constant. Constants can be declared in local, form, module or global scope and can be public or private as for variables. Constants can be declared as illustrated below. 

Public Const gravityconstant As Single = 9.81 

Predefined Visual Basic Constants 

The predefined constants can be used anywhere in the code in place of the actual numeric values. This makes the code easier to read and write. 

For example consider a statement that will set the window state of a form to be maximized. 

Form1.Windowstate = 2 

The same task can be performed using a Visual Basic constant 

Form1.WindowState = vbMaximized 

Data Type Conversion 

Visual Basic functions either to convert a string into an integer or vice versa and many more conversion functions. A complete listing of all the conversion functions offered by Visual Basic is elucidated below. 

Conversion To

Function

Boolean 

Cbool 

Byte 

Cbyte 

Currency 

Ccur 

Date 

Cdate 

Decimals 

Cdec 

Double 

CDbl 

Integer 

Cint 

Long 

CLng 

Single 

CSng 

String 

CStr 

Variant 

Cvar 

Error 

CVErr 



A conversion function should always be placed at the right hand side of the calculation statement. 

Visual Basic Built-in Functions 

Many built-in functions are offered by Visual Basic fall under various categories. These functions are procedures that return a value. The functions fall into the following basic categories that will be discussed in the follwing sections at length. 

·                  Date and Time Functions 

·                  Format Function 

·                  String Functions 

Date and Time Functions in Visual Basic 6 

Not only does Visual Basic let you store date and time information in the specific Date data type, it also provides a lot of date- and time-related functions. These functions are very important in all business applications and deserve an in-depth look. Date and Time are internally stored as numbers in Visual Basic . The decimal points represents the time between 0:00:00 and 23:59:59 hours inclusive.  

The system 's current date and time can be retrieved using the Now, Date and Time functions in Visual Basic . The Now function retrieves the date and time, while Date function retrieves only date and Time function retrieves only the time. 

To display both the date and time together a message box is displayed use the statement given below. 

MsgBox "The current date and time of the system is" & Now 

Here & is used as a concatenation operator to concentrate the string and the Now function. Selective portions of the date and time value can be extracted using the below listed functions. 

Function

Extracted Portion

Year ( ) 

Year (Now) 

Month ( ) 

Month (Now) 

Day ( ) 

Day (Now) 

WeekDay ( ) 

WeekDay (Now) 

Hour ( ) 

Hour (Now) 

Minute ( ) 

Minute (Now) 

Second ( ) 

Second (Now) 



The calculation and conversion functions related to date and time functions are listed below. 

Function

Description

DateAdd ( ) 

Returns a date to which a specific interval has been added 

DateDiff ( ) 

Returns a Long data type value specifying the interval between the two values 

DatePart ( ) 

Returns an Integer containing the specified part of a given date 

DateValue ( ) 

Converts a string to a Date 

TimeValue ( ) 

Converts a string to a time 

DateSerial ( ) 

Returns a date for specified year, month and day 



DateDiff Function 

The DateDiff function returns the intervals between two dates in terms of years, months or days. The syntax for this is given below. 

DateDiff (interval, date1, date2[, firstdayofweek[, firstweekofyear]]) 

Format Function 

The format function accepts a numeric value and converts it to a string in the format specified by the format argument. The syntax for this is given below. 

Format (expression[, format[, firstdayofweek[, firstweekofyear]]]) 

The Format function syntax has these parts: 

Part

Description

Expression 

Required any valid expression 

format 

Optional. A valid named or user-defined format expression. 

firstdayofweek 

Optional. A contant that specifies the first day of the week. 

firstweekofyear 

Optional. A contant that specifies the first week of the year 



 

Getting and Setting the Current Date and Time 

Strictly speaking, Date and Time aren't functions: They're properties. In fact, you can use them to either retrieve the current date and time (as Date values) or assign new values to them to modify the system settings:

Print Date & " " & Time ' Displays "8/14/98 8:35:48 P.M.".
' Set a new system date using any valid date format.
Date = "10/14/98"
Date = "October 14, 1998"

To help you compare the outcome of all date and time functions, all the examples in this section assume that they're executed at the date and time shown in the preceding code snippet: October 17, 2008, 9:25:33 p.m.

The outdated Date$ and Time$ properties can also be used for the same task. They're String properties, however, and therefore recognize only the mm/dd/yy or mm/dd/yyyy formats and the hh:mm:ss and hh:mm formats, respectively. For this reason, it's usually better to use the new $-less functions.

The Now function returns a Date value that contains the current date and time:

Print Now ' Displays "10/17/2008 9:25:33 P.M.".

But the time-honored Timer function returns the number of seconds elapsed from midnight and is more accurate than Now because the Timer function includes fractional parts of seconds. (The actual accuracy depends on the system.) This function is often used for benchmarking a portion of code:

StartTime = Timer
' Insert the code to be benchmarked here.
Print Timer - StartTime

The preceding code suffers from some inaccuracy: The StartTime variable might be assigned when the system tick is about to expire, so your routine could appear to take longer than it actually does. Here's a slightly better approach:

StartTime = NextTimerTick
' Insert the code to be benchmarked here.
Print Timer _ StartTime

' Wait for the current timer tick to elapse.
Function NextTimerTick() As Single
Dim t As Single
t = Timer
Do: Loop While t = Timer
NextTimerTick = Timer
End Function

If you're using the Timer function in production code, you should be aware that it's reset at midnight, so you always run the risk of introducing unlikely but potentially serious errors. Try to spot the bug in this routine, which adds a CPU-independent pause in your code:

' WARNING: this procedure has a bug.
Sub BuggedPause(seconds As Integer)
Dim start As Single
start = Timer
Do: Loop Until Timer _ start >= seconds
End Sub

The bug manifests itself very rarely—for example, if the program asks for a 2-second pause at 11:59:59 p.m. Even if this probability is small, the effect of this minor bug is devastating and you'll have to press Ctrl+Alt+Del to kill your compiled application. Here's a way to work around this issue:

' The correct version of the procedure
Sub Pause(seconds As Integer)
Const SECS_INDAY = 24! * 60 * 60 ' Seconds per day
Dim start As Single
start = Timer
Do: Loop Until (Timer + SECS_INDAY - start) Mod SECS_INDAY >= seconds
End Sub

Building and Extracting Date and Time Values - VB6 Date & Time 

There are many ways to assemble a Date value. For example, you can use a Date constant, such as the following: 

StartDate = #10/17/2008 9:25:33 P.M.# 

but more often you'll build a Date value using one of the many functions that VBA gives you. The DateSerial function builds a Date value from its year/month/day components; similarly, the TimeSerial function builds a Time value from its hour/minute/second components: 

Print DateSerial(2008, 10, 17) ' Displays "10/17/2008"
Print TimeSerial(12, 20, 30) ' Displays "12:20:30 P.M."
' Note that they don't raise errors with invalid arguments.
Print DateSerial(2008, 4, 31) ' Displays "5/1/2008" 

The DateSerial function is also useful for determining indirectly whether a particular year is a leap year: 

Function IsLeapYear(year As Integer) As Boolean
' Are February 29 and March 1 different dates?
IsLeapYear = DateSerial(year, 2, 29) <> DateSerial(year, 3, 1)
End Function 

The DateValue and TimeValue functions return the date or time portions of their argument, which can be a string or a Date expression: 

' The date a week from now
Print DateValue(Now + 7) ' Displays "10/17/2008" 

A bunch of VBA functions let you extract date and time information from a Date expression or variable. The Day, Month, and Year functions return date values, whereas the Hour, Minute, and Second functions return time values: 

' Get information about today's date.
y = Year(Now): m = Month(Now): d = Day(Now)
' These functions also support any valid date format.
Print Year("10/17/2008 9:25:33 P.M.") ' Displays "2008" 

The Weekday function returns a number in the range 1 through 7, which corresponds to the day of the week of a given Date argument: 

Print Weekday("10/17/2008") ' Displays "6" (= vbFriday) 

The Weekday function returns 1 when the date is the first day of the week. This function is locale aware, which means that under different localizations of Microsoft Windows it could consider the first day of the week to be different from vbSunday. In most cases, this condition doesn't affect the structure of your code. But if you want to be sure that 1 means Sunday, 2 means Monday, and so on, you can force the function to return a consistent value under all Windows systems, as follows: 

Print Weekday(Now, vbSunday) 

Although using the optional second argument forces the function to return the correct value, it doesn't change the system localization. If you next call the Weekday function without the second argument, it will still consider the first day of the week to be what it was before. 

Finally you can extract any date and time information from a Date value or expression using the DatePart function, for which the syntax is 

Result = DatePart(Interval, Date, [FirstDayOfWeek], [FirstWeekOfYear]) 

You'll rarely need to resort to this function because you can do most of your calculations using the other functions I've shown you so far. In two cases, however, this function is really useful: 

' The quarter we are in
Print DatePart("q", Now) ' Displays "3"
' The week number we are in (# of weeks since Jan 1st)
Print DatePart("ww", Now) ' Displays "33" 

The first argument can be one of the String constants listed in the following table. For more information about the two optional arguments, see the description of the DateAdd function in the next section. 

Possible values for the interval argument in DatePart, DateAdd, and DateDiff functions.

Setting

Description

"yyyy" 

Year 

"q" 

Quarter 

"m" 

Month 

"y" 

Day of the year (same as d) 

"d" 

Day 

"w" 

Weekday 

"ww" 

Week 

"h" 

Hour 

"n" 

Minute 

"s" 

Second 



Date Arithmetic - VB6 Date & Time 

In most cases, you don't need any special functions to perform date arithmetic. All you need to know is that the integer part in a Date variable holds the date information, and the fractional part holds the time information: 

' 2 days and 12 hours from now
Print Now + 2 + #12:00# ' Displays "8/17/2008 8:35:48 A.M." 

For more sophisticated date math, you can use the DateAdd function, for which the syntax is the following: 

NewDate = DateAdd(interval, number, date) 

The interval is a string that indicates a date or time unit (see table below), number is the number of units you are adding, and date is the starting date. You can use this function to add and subtract date and time values: 

' The date three months from now
Print DateAdd("m", 3, Now) ' Displays "11/14/2008 8:35:48 P.M."
' One year ago (automatically accounts for leap years)
Print DateAdd("yyyy", -1, Now) ' Displays "8/14/2007 8:35:48 P.M."
' The number of months since Jan 30, 2008
Print DateDiff("m", #1/30/2008#, Now) ' Displays "7"
' The number of days since Jan 30, 2008 _ you can use "d" or "y".
Print DateDiff("y", #1/30/2008#, Now) ' Displays "196"
' The number of entire weeks since Jan 30, 2008
Print DateDiff("w", #1/30/2008#, Now) ' Displays "28"
' The number of weekends before 21st century - value <0 means
' future dates.
' Note: use "ww" to return the number of Sundays in the date interval.
Print DateDiff("ww", #1/1/2000#, Now) ' Displays "-72" 

When you have two dates and you want to evaluate the difference between them—that is, the time elapsed between one date and the next—you should use the DateDiff function, for which the syntax is 

Result = DateDiff(interval, startdate, enddate _
[, FirstDayOfWeek[, FirstWeekOfYear]]) 

where interval has the meaning shown in the previous page Building and Extracting Date and Time Values 's table, FirstDayOfWeek is an optional argument that you can use to specify which weekday should be considered as the first day of the week (you can use the constants vbSunday, vbMonday, and so on), and FirstWeekOfYear is another optional argument that lets you specify which week should be considered as the first week of the year. 

Possible values for the FirstWeekOfYear argument in the DateDiff function. 

Constant

Value

Description

vbUseSystem 

Use the NLS API setting. 

vbFirstJan1 

The first week is the one that includes January 1. (This is the default value for this setting.) 

vbFirstFourDays 

The first week is the first one that has at least four days in the new year. 

vbFirstFullWeek 

This first week is the first one that's completely contained in the new year.