Top Banner
VB TIPS & TRICKS To Pause your application for a length of time without a timer control First put this code either in a module as a private function on a form Public Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long) Then when you want to pause something just do this Sleep 1000 'Pause for 1 second Function to Retrieve a Standard Recordset Object. Required: VB5 / VB6 / ADO Most of my application require extensive use of recordsets. I found myself writing the same "with" construct over and over again. To save some time, I built the following function to return a recordset object I can use in any situation: '************************************************************************** 'Function: GetRSTemplate ' 'Description: Builds an empty recordset to return to the calling ' procedure. This is used to initialize a default recordset, yet allow ' the user to change default cursor parameters at this time ' '************************************************************************** Function GetRSTemplate(Optional eCurLoc As CursorLocationEnum, _ Optional eCurType As CursorTypeEnum, _ Optional eLockType As LockTypeEnum) As ADODB.Recordset Dim rsholder As New ADODB.Recordset 'If the user does not include a parameter use defaults. 'The default recordset sets up a static, client side cursor with 'minimal locking With rsholder If eCurLoc = 0 Then .CursorLocation = adUseClient Else .CursorLocation = eCurLoc End If If eCurType = 0 Then .CursorType = adOpenStatic Else .CursorType = eCurType End If No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html
110

VB12

Apr 07, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: VB12

VB TIPS & TRICKS

To Pause your application for a length of time without a timer control

First put this code either in a module as a private function on a form

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

Then when you want to pause something just do thisSleep 1000 'Pause for 1 second

Function to Retr ieve a Standard Recordset Object.

Required: VB5 / VB6 / ADOMost of my application require extensive use of recordsets. I found myself writing the same "with"construct over and over again. To save some time, I built the following function to return a recordsetobject I can use in any situation:'**************************************************************************'Function: GetRSTemplate''Description: Builds an empty recordset to return to the calling' procedure. This is used to initialize a default recordset, yet allow' the user to change default cursor parameters at this time''**************************************************************************Function GetRSTemplate(Optional eCurLoc As CursorLocationEnum, _ Optional eCurType As CursorTypeEnum, _ Optional eLockType As LockTypeEnum) As ADODB.Recordset

Dim rsholder As New ADODB.Recordset

'If the user does not include a parameter use defaults.'The default recordset sets up a static, client side cursor with'minimal locking

With rsholder If eCurLoc = 0 Then .CursorLocation = adUseClient Else .CursorLocation = eCurLoc End If If eCurType = 0 Then .CursorType = adOpenStatic Else .CursorType = eCurType End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 2: VB12

If eLockType = 0 Then .LockType = adLockBatchOptimistic Else .LockType = eLockType End IfEnd With

Set GetRSTemplate = rsholder Set rsholder = NothingEnd Function

Using it is very simple. If you supply no paramters, you get a client side, static cursor with minimallocking:

Private sub command1_click() Dim rs as new ADODB.Recordset set rs = GetRSTemplate()End sub

The function uses the same enumerated values as the recordset properties, so the choices will pop up asthey do when you type in object.proper ty =

Determines the number of workdays within a date range.

I used implicit If Statements (IIF) because they take less lines of code, and this procedure is convolutedenough without making is bigger! In case you aren't familiar with them, they are a hold-over from VBA.The first argument is the expression, the second is what to do if it's true, the third is what to do if it's false.The first part determines the number of days between 2 dates. The second part determines the number ofwhole weeks because each whole week has a Saturday & a Sunday in it.The last part determines if the range spanned a weekend but not a whole week so it can subtract theweekend out.Private Sub FindWorkDays() Dim A1 As Date Dim A2 As Date Dim iWorkDays As Integer

A1 = Text1.Text A2 = Text2.Text

iWorkDays = A2 - A1 + 1 - Int((A2 - A1 + 1) / 7) * 2 - _ IIf(Int((A2 - A1 + 1) / 7) = (A2 - A1 + 1) / 7, 0, _ IIf(WeekDay(A2) < WeekDay(A1), 2, 0)) - _ IIf((WeekDay(A1) = 1 Or WeekDay(A2) = 7), 1, 0)

Label1.Caption = iWorkDays

End Sub

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 3: VB12

Display a Form without a Titlebar .

Often, an application needs a special window without a title bar, the horizontalbar at the top of a window that contains the title of the window. For instance, a splashscreen or a custom context sensitive menu are nothing more than VB forms without titlebars. To make a form appear without a title bar set the following design-time and run-timeproperties.

Properties that must be set at design-time, they are read-only atrun-time:

ControlBox=False ' Turns off Control-menu: Restore, Move, Size,Minimize, Maximize, Close

MaxButton=False ' Turns off Maximize buttonMinButton=False ' Turns off Minimize buttonShowInTaskbar=False ' Hides window in Taskbar

Properties that can be set at either run-time or design-time:Caption="" ' Blanks window title

Making a form invisible, but leaving the controls visible.

This involves using the SetWindowLong API function with the following parameters, GWL_EXSTYLEand WS_EX_TRANSPARENT as constants.

the syntax of the function using the paramters is

dim intresult as long

intresult = setwindowlong(me.hwnd, gwl_exstyle, ws_ex_transparent)

this will make the form referenced by me.hwnd transparent so that the background can be seen but thecontrols can still be accessed.

Making a form stay on top.

This one is for VB programmers who enjoy VB but are new to Visual Basic.Create a Module called ontop.bas in this module put the following constants.

Public Const HWND_NOTOPMOST = -2 Public Const HWND_TOPMOST = -1 Public Const SWP_NOMOVE = &H2 Public Const SWP_NOSIZE = &H1

Declare Function SetWindowPos Lib "user32" (ByVal hwnd as long, ByVal hWndInsertAfter as long, ByVal x as long, ByVal y as long, ByVal cx as long, ByVal cy as long, ByVal wFlags as long) as Long

In the General declarations of the form (ontop.frm) declare a variable lngontop as long

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 4: VB12

Put two command buttons on the form,

command1.caption = &SetOnTop command2.caption = &Make Normal

Code for command1

Private Sub Command1_Click()

lngontop = SetWindowPos = (me.hwnd,HWND_TOPMOST,0,0,0,0,(SWP_NOMOVE or SWP_NOSIZE))

End Sub

Code for command2

Private Sub Command1_Click()

lngontop = SetWindowPos = (me.hwnd,HWND_NOTOPMOST,0,0,0,0,(SWP_NOMOVE or SWP_NOSIZE))

End Sub

The Command1 button set the Always On Top behaviour of the form, while Command2 sets it back tonormal.

Number of Workdays between two dates.

After stumbling around with case statements, tons of if statements I finally found the code to get thenumber of Workdays between two dates, & it only takes a few lines of code.Anyway, here is the code that Excel uses for its NetWorkdays function, and the code i modified to fit VB:

Excel=A2-A1+INT((A2-A1+1)/7*2-IF(INT((A2-A1+1)/7)=(A2-A1+1/7,0,IFWEEKDAY(A2)<WEEKDAY(A1),2,0))-IF(OR(WEEKDAY(A1)=1, pre <lblDays.Caption="intDaysBetween" 0) 1, WeekDay(EndDate)="7)," Or IIf((WeekDay(StartDate)="1" - _0)) 2, WeekDay(StartDate), IIf(WeekDay(EndDate) 0, 7, 1) + StartDate 7)="(EndDate" IIf(Int((EndDate 2* 7 Int(EndDate 1 intDaysBetween Date As EndDate Dim Integer VB WEEKDAY(A2)="7),1,0)"

As you can see i had to replace all the IF's with IIf's (implicit If's). The first partdetermines the number of days between the 2 dates. The next part determines the number of whole weeksbetween because of the Saturdays & Sundays. Then the last part determines if the dates spanned aweekend where the start date day would be smaller that the end date day.

Lostfocus of a text box control.

This tip is w.r.t the problem of going in a loop when performing validation on the lostfocus of a text boxcontrol.

I have seen that many programmers face this problem and to solve this problem VB 6.0 has introduced aValidate event also.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 5: VB12

But as i have been using VB 4.0 from a long time i have found a simpler trick to handle this problem,which works on VB 4.0 and VB 6.0

Place two text boxes on the form and see that the initial text property is blank.

Paste the following code on the form:

Private Sub Text1_LostFocus() If Val(Text1.Text) > 0 Then Text1.SetFocus MsgBox "Value cannot be greater than zero." End IfEnd Sub

Private Sub Text2_LostFocus() If Val(Text2.Text) = 0 Then Text2.SetFocus MsgBox "Value cannot be equal to zero." End IfEnd Sub

And now run the application. Type some value in text1 and do a lostfocus and everything will work fine.Now change the code and do a setfocus after the message is displayed on the lostfocus of both the textboxes. That is change the code to :

Private Sub Text1_LostFocus() If Val(Text1.Text) > 0 Then MsgBox "Value cannot be greater than zero." Text1.SetFocus End IfEnd Sub

Private Sub Text2_LostFocus() If Val(Text2.Text) = 0 Then MsgBox "Value cannot be equal to zero." Text2.SetFocus End IfEnd Sub

Now run the application.Type some value in the first text box and perform a lostfocus and you will seethat everything goes in a loop and the only solution is to perform an abnormal termination of theapplication..

Hence the trick is that if any validation is to be done and you need to place the control back on the textbox then perform a setfocus before the Message is displayed instead of performing it after the message isdisplayed.

Map and Disconnect network dr ive letter .

I really think VBers will like this little application. It answers several questions:How can I map a networked Drive Letter

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 6: VB12

How can I disconnect a networked Drive LetterHow can I Open a file or application with VB without using the limited "SHELL" command

I have included the compiled app and its source code. You will need VB6 to open this project, but it will workin any version of VB from 32-bit 4.0 on up!

Invalid use of null er ror .A nice way to avoid the 'invalid use of null' error is to use the VB build in function VarType. Use thefollowing code to check for the vartype:dim retvaldim retvaltype

'add code to retrieve information from the recordset and assign it to the retval

retvaltype = VarType(retval)

if retvaltype = 2 then retval = "" ' or you could put a 0(zero) if it is a numeric fieldelse reval = retvalend ifThis should be done only with small amount of variables declared as variant as it take more overhead todelcare a variant, however if you need a fast way to solve this problem it works.

How to create dll files using Visual Basic.It is always said that the only language for creating dll is C or C++, but VB is also very powerful and easyto use for the creation of dll files. Here is a sample of how u can create a small message dll file and thencall it in your program, the way you call windows dll.Open a new ActiveXDll project from New Project Menu in VB. change the name of class1 to message andset the following properties asProperties of class Message

Name MessageDataBindingBehavior 0-VBNoneDataSourceBehavior 0-VBNoneInstancing 5-MultiuseMTSTransactionMode 0-NotAnMTSObjectPersistable 0-NonPersistableThere are four public proceudres for message dialogue box. You can write any type of procedure orfunction, but for simplicity I wrote procdures that only display message boxes.Public Sub information(details, title)MsgBox details, vbInformation, titleEnd Sub

Public Sub exclaim(details, title)MsgBox details, vbExclamation, titleEnd Sub

Public Sub question(details, title)MsgBox details, vbQuestion, titleEnd Sub

Public Sub critical(details, title)

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 7: VB12

MsgBox details, vbCritical, titleEnd SubFrom the File menu, choose Make Project1 Dll.. Since we haven't change the name of project, the defaultname is project1. save the program.Now open a new project in VB. Go to the Project Menu and choose References and check the Project1 asshown below.Create a form and place two text boxes on that form. Name them txtDescription and txtTitle. Also placefour Option button on the form and name them, optInformation, optQuestion, optCritical, and optexclaimand a command button name cmdRun as shown

Option ExplicitPrivate mess As New message

Private Sub cmdRun_Click()

If optInformation = True Then mess.Information txtDescription, txtTitleElseIf optQuestion = True Then mess.question txtDescription, txtTitleElseIf optCritical = True Then mess.critical txtDescription, txtTitleElse mess.exclaim txtDescription, txtTitleEnd If

End Sub

Now write some text in description box and the title text in title text box and also choose the message typeand press the command button and u will see the appropriate message coming through the dll file.

Find the number of workdays between two dates.

Like Bill Mosca, I had to find the number of workdays between two dates. This solution doesn’ t haverules, the starting day may be any day of the week. Workdays are Monday through FridayPut two textboxes and a command button on a form, and call them;txtDagenData2wdHere’s the code I came up with:Please Note: Code in dutchPrivate Sub wd_Click()If Not IsDate(txtDagen.Text) Then MsgBox "U moet een datum invullen ( Datum 1 )" txtDagen.Text = "" Exit Sub

End If

If Not IsDate(Data2.Text) Then MsgBox "U moet een datum invullen ( Datum 2 )" Data2.Text = ""

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 8: VB12

Data2.SetFocus Exit Sub

End If'================Dagnummer$ = ""zat$ = ""bij$ = ""Dagnummer1$ = ""Dagnummer2$ = ""Rekendagen$ = ""Verschil$ = ""weken$ = ""Overdagen$ = ""aww$ = ""odb$ = ""Weekdagen$ = ""awr$ = ""aftel$ = ""Werkdagen = ""

Verschil$ = DateDiff("d", txtDagen.Text, Data2.Text, 2)Dagnummer$ = DatePart("W", txtDagen.Text, 2)Dagnummer2$ = DatePart("W", Data2.Text, 2)

Overdagen$ = Format$(7 - Val(Dagnummer$))Rekendagen$ = Format$(Val(Verschil$) - Val(Overdagen$))weken$ = Format$(Int(Val(Rekendagen$) / 7))

Weekdagen$ = Format$(Val(Rekendagen$) - (7 * Val(weken$)))

aww$ = Format$(Val(weken$) * 5)awr$ = Format$(Val(aww$) + Val(Weekdagen$))

'========

If Val(Dagnummer$) = 6 Then odb$ = Format$(Val(Overdagen$) - 1) aftel$ = "1"ElseIf Val(Dagnummer$) = 7 Then odb$ = Format$(Val(Overdagen$) - 0) aftel$ = "0"Else odb$ = Format$(Val(Overdagen$) - 2)End If'==========

If Val(Dagnummer2$) = 6 Then zat$ = "-1"Else zat$ = "0"End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 9: VB12

If Val(Dagnummer$) = 6 Or Val(Dagnummer$) = 7 Then bij$ = "0" Werkdagen = Format$(Val(awr$) + Val(odb$) + Val(zat$))Else bij$ = "1" Werkdagen = Format$(Val(awr$) + Val(odb$) + Val(bij$) + Val(zat$))End If

'==================

MsgBox "Aantal werkdagen = " & Werkdagen

End Sub

This function checks the validity of a credit card number .Returns 'True' If the number is in a valid format.Returns 'False' If the number is in an invalid format.Descr iption:This algorithm should work with all credit cards.If a card validates with this code it doesn't mean that the card is actually good, it just means that thenumbers are arranged in a valid format. If they don't validate then you've saved some time because youdon't have to process the card to find out that it is defiantely bad. I use this function in CGI forms thatprocess credit card orders.Function CheckCard(CCNumber As String) As Boolean Dim Counter As Integer, TmpInt As Integer Dim Answer As Integer

Counter = 1 TmpInt = 0

While Counter <= Len(CCNumber) If (Len(CCNumber) Mod 2) Then TmpInt = Val(Mid$(CCNumber, Counter, 1)) If Not (Counter Mod 2) Then TmpInt = TmpInt * 2 If TmpInt > 9 Then TmpInt = TmpInt - 9 End If Answer = Answer + TmpInt Counter = Counter + 1 Else TmpInt = Val(Mid$(CCNumber, Counter, 1)) If (Counter Mod 2) Then TmpInt = TmpInt * 2 If TmpInt > 9 Then TmpInt = TmpInt - 9 End If Answer = Answer + TmpInt Counter = Counter + 1 End If Wend

Answer = Answer Mod 10

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 10: VB12

If Answer = 0 Then CheckCard = TrueEnd Function

Find the number of workdays between two datesI had to find the number of workdays between two dates (including Saturday as a possible starting day).The number of days were grouped into these ranges: 1 day, 2 days, 3 days, 5+days, 10+days, and 30+days.The rules were No input on Sundays and starting dates were only Monday through Friday, but endingdates might be on Saturdays. Here's the code I came up with: Select Case DaysBetween Case 0 To 6 Select Case DaysBetween Case 0, 1 rs.Edit rs("Days") = 1 rs.Update Case 2 rs.Edit rs("Days") = 2 rs.Update Case 3 If WeekDay(Date2) = vbMonday Then rs.Edit rs("Days") = 1 rs.Update Else rs.Edit rs("Days") = 3 rs.Update End If Case 4 If WeekDay(Date2) = vbMonday Then rs.Edit rs("Days") = 2 rs.Update ElseIf WeekDay(Date2) = vbTuesday Then rs.Edit rs("Days") = 3 rs.Update Else rs.Edit rs("Days") = 3 rs.Update End If

Case 5 '5 to 9 -->5+ If WeekDay(Date2) < vbFriday Then rs.Edit rs("Days") = 3 rs.Update ElseIf WeekDay(Date2) >= vbFriday Then rs.Edit rs("Days") = 5 rs.Update

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 11: VB12

End If Case 6 If WeekDay(Date2) < vbThursday Then rs.Edit rs("Days") = 3 rs.Update ElseIf WeekDay(Date2) >= vbThursday Then rs.Edit rs("Days") = 5 rs.Update End If End Select Case 7 To 11 '5 to 9 -->5+ rs.Edit rs("Days") = 5 rs.Update Case Is > 11 WeeksBetween = DateDiff("w", Date1, Date2) Select Case WeeksBetween Case 1 To 5 '10 to 29 -->10+ rs.Edit rs("Days") = 10 rs.Update Case Is > 5 '30+ rs.Edit rs("Days") = 30 rs.Update End Select End Select Else 'if bill is a Send Back rs.Edit rs("Days") = 0 rs.Update End If rs.MoveNext Loop

Return True if no value is passed

If you use a typed variable as optional argument in a Function or Sub you can't use "ISMISSING" functionto determine whether it is initialized or not.To solve this you can use "Empty" keyword as follows, Public Function MyFun (Optional ByVal sOptVaras String) As Boolean if sOptVar = Empty then MyFun = True Else MyFun = False End if End FunctionThis function returns True if no value is passed to the optional variable sOptVar, else returns False.This Works in VB5.0.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 12: VB12

Call a value from your enumeration

Everybody talks about "How useful enumeration is". Here goes a little piece of code that reallydemonstrates that statement is correct.With a little help from a property let and property get, you can call a value from your enumeration withouthaving to remember the description you previouslly coded inside of your enumeration since it will pops upfor you.* Here goes the code:'Add this code to a module.basDim mForm As ByteEnum FromForm FormNameA = 1 FormNameB = 2 FormNameC = 3End Enum

Property Get SetForm() As FromForm SetForm = mFormEnd Property

Property Let SetForm(Value As FromForm) mForm = ValueEnd Property

'Add this to a command button on your application'to associate with a formSetForm = FormNameB

Snds parameters in an INDEX format to a class

We are developing a crystal report print engine dll, that will be called from another dll, and will generatereports.On the first tier, we want to pass the report parameters to the second tier. Although we know we can dothat on an array manner, we found out that sending the parameters in an INDEX manner should make theprocess much more friendly for the first tier developer. Therefore, the code bellow, sends parameters in anINDEX format to a class. When the class receives the parameters, it builds an array that can be used inthe class as desired.On the first tier the code is something like the one bellow.* After referencing the DLL or making a class named PrintEngineDim ObjPrint as PrintEngine.EngineSet ObjPrint = New EngineobjPrint.StoreProcParam(0) = Variable 1objPrint.StoreProcParam(1) = Variable 2objPrint.StoreProcParam(2) = Variable 3objPrint.StoreProcParam(3) = Variable 3and so on......On second tier the code is something like the one bellow.Private mStoreprocparam() As VariantPublic Property Let StoreProcParam(Index As Integer, value As String)

ReDim Preserve mStoreProcParam(Index)Let mStoreProcParam(Index) = Value

End property

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 13: VB12

Then I use the variant mStoreProcParam on the second tier to work with the received parameters.The main point for the sample above is the property Let StoreProcParam(Index As Integer, value AsString). This property receives one index and one value at a time and stores it in the arraymStoreProcParam(). Then, that Array can be used in a lot of different ways.

How to use MSFlexGr id to display data via ADO method

We tried this example to show how to use MSFlexGrid to display data via ADO method, and also to showa simple SQL query. first we set up ADO object, and connected with a back end Sybase database, opened atable, which called mirtb_patient, we used a MSFlexGrid for 25 columns(fields), and specified two loops,variable ii for row(record), oo for column. This prepared query can get the data from a Sybase via ADO,and dispaly them on the MSFlexGrid. Notice that when it finish, all opening objects and methods shouldbe closed.

Option ExplicitDim Cn As New ADODB.ConnectionDim rs As ADODB.Recordset

'Use a connecting string or Connection object here

Dim sSQL As StringDim sOut As String

Private Sub connect_cmd_Click()

' Set ii as the row counter

Dim ii As Long

' Set oo as the column counter

Dim oo As Integer

'ADO Demo, it populates data with MSFlexGrid !

If Cn.State = adStateOpen Then MsgBox "ADO Connection Successful!"End If

' Set up SQL calling

sSQL = "Select * from mirtb_patient"rs.Open sSQL, Cn, adOpenDynamicsOut = ""

ii = 0

' To see if end of the table?While rs.EOF <> TrueDBGrid1.Rows = ii + 1iii = 1

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 14: VB12

' Loop for the column, we just used 25 columns for display!

For oo = 0 To 24DBGrid1.TextMatrix(ii, oo) = rs.Fields(oo)Next ooii = ii + 1

' Move to next record

rs.MoveNextWendEnd Sub

Private Sub Form_Load()

'Define a Command object for the connection

Set Cn = New ADODB.ConnectionSet rs = New ADODB.RecordsetCn.ConnectionString = "DSN=TESTRCH01;UID=ADOTRY;PWD=ADOTRY;"Cn.ConnectionTimeout = 100Cn.OpenEnd Sub

Private Sub quit_cmd_Click()

' To close objects rs and cn etc., they shoud be closed here!

rs.CloseSet rs = NothingCn.CloseSet Cn = NothingUnload MeEnd Sub

Quick single line toggle for 1/0-type boolean values

This is for toggling boolean values that flip between 1 and zero as opposed to -1 and zero, which are VB'sbuilt-in boolean values.One common place I use it is toggling checkboxes/checkable menu options. Both of these use as their"checked" status either vbUnchecked (0) or vbChecked (1).The standard method for toggling these is to use an If-Then statement:if check_value = vbChecked Then check_value = vbUncheckedElse check_value = vbCheckedEnd IfThere is nothing inherently wrong with this, except that it takes up 5 lines of code, and the alternative ofputting it on one line, separated by colons is messy. This means extra scrolling space which can be ahindrance, especially if you have already long procedures.Unfortunately, you can't use the Not operator as in:

check_value = Not check_value

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 15: VB12

because Not (0) is -1, and worse, Not (1) is -2. This problem arises because the Not() function performs abitwise NOT, rather than a true logical NOT. As a result, this only works with "true" boolean values (-1/0).The solution which hit me is simply to add 2:

check_value = (Not check_value) + 2hey... works like a charm!

How to save a brande new WAV file using mciSendStr ing API

Shows you how to save a brand new WAV file using the mciSendString API (Doen't use the MCI Controlthat comes with VB5!) It is really easy to do that. I learned it after studying this API for a while. I couldn'tget the MCI Control to save a WAV file though! I don't know why! If any body could, just e-mail it to meand I will see how it is possible to do. :-)DownloadWAVESAVE.ZIP <wavsave.zip> (File size 1.4K)

Making the Close button (X) on a form disabled

Ever wonder how those Setup programs have their X button on caption bar disabled, so you can't closethem? Well, now you can do it, when you download this!DownloadCANTCLOS.ZIP </vb-mag/9808/item/cantclos.zip> (File size 1.7K)

Even or Odd - Update

the tip featured in your current issue to tell if a number is even or odd, works v_e_r_y slow. It does a lot oftype conversion between numbers and strings and unnecessary, slow string manipulation. It willremarkably slow down the machine if used in a loop and uses a dirty kind of type casting because aninteger value is used as a return value of a boolean type function (!). In addition, it will only work withVisual Basic.There are at least two much more efficient and simple ways to tell if a number is odd or even; bothexamples will store "TRUE" in the variable "bool_IsEven" if the number is even and will work in nearlyall programming languages:

a) bool_IsEven = int_Number MOD 2 = 0 b) bool_IsEven = int_Number AND 1 = 0

How to disable Ctr l Alt Del.

With Windows 95 it is possible to disable CTRL-ALT-DEL, CTRL-ESC and ALT-TAB by claiming to bethe current screen saver. Sample code can be found at http://www.vbonline.com/vb-mag/qaweb/win95/cad.htm in the new qaweb section of VB Online Magazine. To start an application youhave a few options. Normally the Startup group is used, but since this sort of application must beinaccessible to the general user you need to place it in the registry. There are three keys of interest:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunHKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceHKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices

All entries under these three keys are started during the bootup process and your application should belisted under one of them. The "Run" key names applications to run every time, as does the "RunServices"key. The difference is when they start during the boot process. You probably want to use the Run key, butyou can try both and see what the difference is. The RunOnce key will run the next time Win95 starts, butis then purged. This is a good place to put applications that complete a setup process or a cleanup.

List Box To L ist Box - VB5 Professional

Here is another way to move data from one list box to another and back. The four buttons ( ADD, ADDALL, REMOVE and REMOVE ALL) are a control array and the subroutine FourButtons handles all

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 16: VB12

movements between the two list boxes. I tried to use the least amount of code. This app is an unattendedbulk printing app.

Private Sub FourButtons(ByVal Index As Integer)Screen.MousePointer = 11Select Case Index Case 0 ' Add selected contractId from List1 to List2 If List1.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List1.ListIndex = -1 Then 'nothing is selected List1.SetFocus List1.Selected(0) = True 'select the first item in the list. End If DoEvents List2.AddItem List1.Text List1.RemoveItem List1.ListIndex

Case 1 ' Add All ContractIds from List1 to List2 If List1.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List1.ListIndex = -1 Then List1.SetFocus List1.Selected(0) = True End If DoEvents For i = (List1.ListCount - 1) To 0 Step -1 List2.AddItem List1.List(i) DoEvents Next i List1.Clear

Case 2 ' Remove selected contractId from List2 to List1 If List2.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List2.ListCount = 0 Then Exit Sub If List2.ListIndex = -1 Then List2.SetFocus List2.Selected(0) = True End If

List1.AddItem List2.Text List2.RemoveItem List2.ListIndex

Case 3 ' Remove All ContractIds From List2 to List1 If List2.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 17: VB12

If List2.ListCount = 0 Then Exit Sub If List2.ListIndex = -1 Then 'nothing is selected. List2.SetFocus 'set focus. List2.Selected(0) = True 'select first item in list. End If For i = (List2.ListCount - 1) To 0 Step -1 List1.AddItem List2.List(i) DoEvents Next i List2.Clear

End SelectScreen.MousePointer = 0End Sub

How to wr ite a Screen Saver .

The basic requirements for creating a screen saver are:In the properties for your application set the title to:

SCRNSAVE: name

The 'name' part will appear on the list of available screen savers in the control panel. Note thatthis is not the title of the form, it is the application title and must be set in the project properties.

When you compile the program use .SCR for the extension instead of .EXE as normal. Place thecompiled code in the Windows\System directory (it can also go in Windows, but System ispreferred)

When your application starts check for a previous instance and stop if one is found:

Sub Form_Load() If App.PrevInstance Then Unload Me ' NEVER use END! Exit Sub End If

End Sub

Check the command line for switches:

/s setup mode - display/update configuration options only /p nnn preview mode - "nnn" is a handle to the preview window /a password support check

If the screen saver is to run normally use the following to tell Windows that you are taking over as ascreen saver (this will disable ALT-TAB and CTRL-ALT-DEL and prevent more instances frombeing started):

Private Const SPI_SCREENSAVERRUNNING=97 Private Declare Function SystemParametersInfo Lib "user32" _ Alias "SystemParametersInfoA" (ByVal uAction As Long, _ ByVal uParam As Long, lpvParam As Any, _ ByVal fuWinIni As Long) As Long SystemParametersInfo SPI_SCREENSAVERRUNNING, 1, ByVal 1&, False

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 18: VB12

Before your code terminates tell Windows you are leaving with: SystemParametersInfo SPI_SCREENSAVERRUNNING, 0, ByVal 1&, False

For more information, including sample code that handles password protected screen saverscheck http://www.arcatapet.com/vb.html or http://www.tiac.net/users/lvasseur/

Reading data from a database to display on a form is null fields.

To prevent an 'invalid use of null' error occurring when reading data from a database use the followingsyntax:

Text fields:Form1.text1.text = "" & myRecordset("TextName")

Numeric fields:Form1.Option1.Value = 0 & myRecordset("NumricField")

How to place your application in the System Tray.

Applies to Win95 and WinNT

Both Windows95 and WindowsNT have that neat new feature called the system tray where you can placeyour application. This is easily done via the Windows API called "Shell_NotifyIcon" which manages theTaskbar which the system tray is part of.There are a couple of tricky things that you need to keep in mind when using this function. First, theapplication needs to be visible (but not necessarily seen--you can set its Top & Left to -10000) and youalso need to know how to handle callback functions. If your not sure what a callback function is then stophere (you should learn about callback functions before proceeding).First, place the declares into a bas module:' These tell you what is happening in the system tray (over your icon)Public Const WM_MOUSEISMOVING = &H200 ' Mouse is movingPublic Const WM_LBUTTONDOWN = &H201 'Button downPublic Const WM_LBUTTONUP = &H202 'Button upPublic Const WM_LBUTTONDBLCLK = &H203 'Double-clickPublic Const WM_RBUTTONDOWN = &H204 'Button downPublic Const WM_RBUTTONUP = &H205 'Button upPublic Const WM_RBUTTONDBLCLK = &H206 'Double-clickPublic Const WM_SETHOTKEY = &H32

' The API CallPublic Declare Function Shell_NotifyIcon Lib "shell32" _ Alias "Shell_NotifyIconA" _ (ByVal dwMessage As enm_NIM_Shell, pnid As NOTIFYICONDATA) AsBoolean

' User defined type required by Shell_NotifyIcon API callPublic Type NOTIFYICONDATA cbSize As Long hwnd As Long uId As Long uFlags As Long uCallbackMessage As Long

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 19: VB12

hIcon As Long szTip As String * 64End Type

' This is an Enum that tells the API what to do...' Constants required by Shell_NotifyIcon API call:Public Enum enm_NIM_Shell NIM_ADD = &H0 NIM_MODIFY = &H1 NIM_DELETE = &H2 NIF_MESSAGE = &H1 NIF_ICON = &H2 NIF_TIP = &H4 WM_MOUSEMOVE = &H200End Enum

Public nidProgramData As NOTIFYICONDATA

Place this code in Form_Load():

Private Sub Form_Load()

' Hide the form With Me .Top = -10000 .Left = -10000 .WindowState = vbMinimized End With

With nidProgramData .cbSize = Len(nidProgramData) .hwnd = Me.hwnd .uId = vbNull .uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE ' This is the event that will trigger when stuff happens .uCallbackMessage = WM_MOUSEMOVE .hIcon = Me.Icon .szTip = "Lock Your System" & vbNullChar End With

' Call Notify... Shell_NotifyIcon NIM_ADD, nidProgramData

End Sub

This goes into the Form_MouseMove event:

' Name: Form_MouseMove

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 20: VB12

'' Purpose: Processes the Events from the TaskBar...'' Inputs: None'' Returns: None'' Revision: James E. Bettone 12/02/1997'Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X AsSingle, Y As Single)

On Error GoTo Form_MouseMove_err:

' This procedure receives the callbacks from the System Tray icon. Dim Result As Long Dim msg As Long

' The value of X will vary depending upon the scalemode setting If Me.ScaleMode = vbPixels Then msg = X Else msg = X / Screen.TwipsPerPixelX End If

Select Case msg Case WM_LBUTTONUP

' process single click on your iconCall Command1_Click()

Case WM_LBUTTONDBLCLK' Process double click on your icon

Case WM_RBUTTONUP' Usually display popup menu

Case WM_MOUSEISMOVING' Do Somthing...

End Select

Exit Sub

Form_MouseMove_err: ' Your Error handler goes here!

End Sub

When your Application executes, it will head right into the System Tray. It is up to you to program in thecontext menus and to process the callback messages.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 21: VB12

Attaching and manipulating PictureBox and TextBox on the CommandButton.

When images are needed to be inserted at the Command Button control, there are two ways.

First, the Command Button style property is set 1(Graphic) and the shape of the image can be changedaccording that the user presses the mouse button up or down. However, the images should be placed at afixed position, and both images and texts can't be displayed. Second, we can put the PictureBox which hasthe Enabled property False on the Command Button control. In this case, we can't make use of a functionof the PictureBox. That is, we can't change the BorderStyle according that the mouse pointer is in thePictureBox or out of the PictureBox. If PostMessage Windows API is used, we can solve this problem.Suppose there are two bitmap files, button.bmp and camera.bmp.Private Const WM_LBUTTONDOWN = &H201Private Const WM_LBUTTONUP = &H202Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _ ByVal lParam As Long) As Long

Private Sub Form_Load() Picture1.TabStop = False Picture1.BorderStyle = 0End Sub

Private Sub Command2_Click() Unload MeEnd Sub

Private Sub Picture1_MouseMove(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Picture1.BorderStyle = 1End Sub

Private Sub Command1_MouseMove(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Picture1.BorderStyle = 0End Sub

Private Sub Command1_MouseDown(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Form1.Picture1.Picture = LoadPicture("button.bmp")End Sub

Private Sub Command1_MouseUp(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Form1.Picture1.Picture = LoadPicture("camera.bmp")End Sub

Private Sub Picture1_MouseDown(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Ret = PostMessage(Form1.Command1.hwnd, WM_LBUTTONDOWN, _ wParam, lParam)End Sub

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 22: VB12

Private Sub Picture1_MouseUp(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Ret = PostMessage(Form1.Command1.hwnd, WM_LBUTTONUP, _ wParam, lParam)End Sub

" ShowInTaskBar" proper ty of a VB Form at runtime.

Option Explicit'--------------------------------

' This code will set "ShowInTaskBar" property' of a VB Form at runtime. I haven't been able' to change this property without unloading the' form. This code could be useful when used in' conjunction with a user-chosen preference.' (Maybe you can think of a good use for it.)' Comments, improvements? Please forward to:' Joe LeVasseur'-----------------------------------------------Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" (ByVal hwnd As Long, _ ByVal nIndex As Long) As LongPrivate Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" (ByVal hwnd As Long, _ ByVal nIndex As Long, ByVal dwNewLong As Long) As Long'----------------------------Private Const GWL_EXSTYLE = (-&H14)Private Const WS_EX_TOOLWINDOW = &H80'----------------------------Private Sub Form_Initialize() Call SetStyleEnd SubPrivate Sub SetStyle() Dim lWindowStyle&, lRetVal& Debug.Print Second(Now) ' 50/50 chance If (Second(Now) Mod 2) Then lWindowStyle = GetWindowLong(hwnd, GWL_EXSTYLE) lWindowStyle = lWindowStyle And WS_EX_TOOLWINDOW lRetVal = SetWindowLong(hwnd, GWL_EXSTYLE, lWindowStyle) End IfEnd Sub

Delaying a VB app for a set number of M inutes, Seconds.

Option ExplicitDim StopTheTimer As Boolean

Private Sub Command1_Click() Dim lRetval&

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 23: VB12

lRetval = Delay(1, 5, StopTheTimer) If lRetval = 0 Then MsgBox "Time's up!" Else MsgBox "You cancelled!" End IfEnd SubPrivate Sub Command2_Click() StopTheTimer = TrueEnd Sub

Public Function Delay(Mins%, Secs%, Optional ByRef StopFlag) As Long Dim EndOfDelay EndOfDelay = DateAdd("n", Mins, Now) EndOfDelay = DateAdd("s", Secs, EndOfDelay) Delay = 0 Do While (Now < EndOfDelay) DoEvents If Not IsMissing(StopFlag) Then If StopFlag Then Delay = 1 StopFlag = False Exit Do End If End If LoopEnd Function

Easy Transparent Scrolling text on picture

The idea is from the scrolling text I read in a old "tips&tricks" and part of the listing is from it. Create aform and load on it a <<.bmp>> picture, by picture property. Create a label and a timer on the form. Theproperties of the label you must change are BackStyle=3D0 transparent and borderstyle 0=3DNome. Thentype the statements in the subs:Sub Form_Load()Me.ShowLabel1.Caption =3D "Hi!! scroll Test.."Label1.ForeColor =3D &HFFScaleMode =3D 3 theleft =3D ScaleWidth / 2

thetop =3D ScaleHeight

Timer1.Enabled =3D True Timer1.Interval =3D 10End Sub

Sub Timer1_Timer()Label1.Top =3D thetop thetop =3D thetop - 1 If thetop < -p1hgt Then Timer1.Enabled =3D False

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 24: VB12

Txt$ =3D "Finished With Scrolling" CurrentY =3D ScaleHeight / 2 CurrentX =3D (ScaleWidth - TextWidth(Txt$)) / 2 Print Txt$ End IfEnd Sub

No L istbox.ScrollPos member?

Whilst working on a current project the requirement to scroll an array of listboxes simultaneously croppedup. I was surprised to discover that there is no Listbox.ScrollPos member of the ListBox control and sohad to resort to the windows API to overcome this oversight. The results of which are included below.Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwndAs Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long

' *** ListBox Scroll Event ***Private Sub lst_Ranges_Scroll(Index As Integer)Dim I As Integer, Pos As IntegerStatic bScrolling As Boolean

If Not bScrolling Then bScrolling = True Pos = GetScrollPos(lst_Ranges(Index).hwnd, SB_VERT) For I = 0 To 3 If I <> Index Then SendMessage lst_Ranges(I).hwnd, WM_VSCROLL,MakeLong(SB_THUMBPOSITION, Pos), SB_THUMBPOSITION End If Next bScrolling = FalseEnd IfEnd Sub

' *** MakeLong Method ***Private Function MakeLong(LOWORD As Integer, HIWORD As Integer) As LongMakeLong = Bitwise_OR(LOWORD, Bitwise_SHL(HIWORD, 16))End Function

I hope this will be of some use to somebody someday, I know that I was surprised when I discovered thelack of a ScrollPos Member.

The " AlwaysOnTop" proper ty.By Joe [email protected] paste the code below into the form that you need to have the "AlwaysOnTop" property. Syntaxwould be like this-[FormName].AlwaysOnTop= True Note the commented code in the Resize event, theform loses the "AlwaysOnTop" property if it is minimized. I think that under most circumstances a"AlwaysOnTop" window would probably be a fixed dialog and therefore not minimizable. One othercaveat- this code may or may not work in the IDE. (I've seen both.)__________snip____________________________________Option Explicit'------------------' Paste this into a form and you' will have a new property-AlwaysOnTop.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 25: VB12

' You then can use it like any other' property- [FormName].AlwaysOnTop= True' Joe LeVasseur'------------------Private Const HWND_TOPMOST = -&H1Private Const HWND_NOTOPMOST = -&H2Private Const SWP_NOSIZE = &H1Private Const SWP_NOMOVE = &H2'------------------Private Declare Sub SetWindowPos Lib "user32" (ByVal hWnd As Long, _ ByVal hWndInsertAfter As Long, ByVal x As Long, _ ByVal y As Long, ByVal cx As Long, ByVal cy As Long, _ ByVal wFlags As Long)'------------------Private bOnTopState As BooleanPublic Property Let AlwaysOnTop(bState As Boolean) Dim lFlag As Long On Error Resume Next If bState = True Then lFlag = HWND_TOPMOST Else lFlag = HWND_NOTOPMOST End If bOnTopState = bState Call SetWindowPos(Me.hWnd, lFlag, 0&, 0&, 0&, 0&, _ (SWP_NOSIZE Or SWP_NOMOVE))End PropertyPublic Property Get AlwaysOnTop() As Boolean AlwaysOnTop = bOnTopStateEnd Property'------------------Private Sub Form_Resize()' Only need this if form can be' minimized.(Loses the setting.) 'AlwaysOnTop = bOnTopStateEnd Sub_________snip___________________________________________

Here's a another way to speed up looping through a recordset

There was a good tip for speeding up looping through a recordset in this tips section. (I have included itbelow for reference) However, if you have the option, there is another way to perform an operation onevery member of a recordset that will execute much faster than any recordset operation, use a SQLUPDATE statement to modify the records. That way, the modification executes on the database server,and gets whatever optimizations your database engine provides. For example, to give all yourlongstanding customers a discount, you could use the following SQL statement in place of any recordset:

UPDATE Customers SET Discount = 0.10 WHERE CustSince <= 1993This could take the place of getting a recordset with the SQL:SELECT Discount FROM Customers WHERE CustSince <= 1993and then needing to navigate the whole recordset setting each Discount to 10%.

--------------------------------------------------------------------------------------------------------------------------------------Accessing Databases

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 26: VB12

This tip is on accessing databases. For performing an operation inevery record of a Table or RecordSet (for example you could want to update some fields, or retrieve some information), generallythis code is used.

Do ... ... MyDynaset.MoveNext Loop Until MyDynaset.EOF

Bat if you use this code

Dim k As Long, j As Long

MyDynaset.MoveLast j = MyDynaset.RecordCount MyDynaset.MoveFirst

For k = 1 to j ... ... MyDynaset.MoveNext Next

you should notice is 30% speed increase from the first code. I tried this code with a MDB file with17000 records, and with a MDB file with 500 records. They both work well. The reason? Of coursebecause the second code does not check the EOF condition every iteration (even if it must go to the lastrecord and then to the first record)! Maybe, if the recordset is small you may not notice anyimprovement, but in this case, processing time is short anyway. I found this code does not improveprocessing time in Delphi. I think it's because Delphi EXE is compiled and not p-code.

Here's a efficient IsEven function

Function IsEven( n as Integer) As Boolean IsEven = Not -(n And 1) End Function If you want an IsOddfunction, just omit the Not.

Move elements from one list box to another

This is something I feel a few people might find to be useful. Basically it allows elements to be movedbetween two list boxes as well as conditionally enabling an Execute button if there are any elements in thesecond list box. You should first design a form that looks like this:

Private Sub cmdLeft2Right_Click() If lstList1.ListCount > 0 Then List_Refresh lstList1, lstList2 cmdExecute.Enabled = True End If If lstList1.ListCount > 0 Then cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True Else

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 27: VB12

cmdLeft2Right.Enabled = False cmdAll2Right.Enabled = False cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True End IfEnd Sub

Private Sub cmdAll2Right_Click() Move_All_Items "Right", lstList1, lstList2 cmdLeft2Right.Enabled = False cmdAll2Right.Enabled = False cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True cmdExecute.Enabled = TrueEnd Sub

Private Sub cmdAll2Left_Click() Move_All_Items "Left", lstList1, lstList2 cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True cmdAll2Left.Enabled = False cmdRight2Left.Enabled = False cmdExecute.Enabled = FalseEnd Sub

Private Sub cmdRight2Left_Click() If lstList2.ListCount > 0 Then List_Refresh lstList2, lstList1 If lstList2.ListCount > 0 Then cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True Else cmdExecute.Enabled = False cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True cmdAll2Left.Enabled = False cmdRight2Left.Enabled = False End IfEnd Sub

Public Sub Move_All_Items(Direction As String, List1 As Control, List2 As Control)Dim Count As Integer Select Case Direction Case "Left" For Count = 0 To List2.ListCount - 1 List1.AddItem List2.List(Count) List2.Selected(Count) = 0 Next Count List_Refresh List2, List1 List2.Clear Case "Right" For Count = 0 To List1.ListCount - 1 List2.AddItem List1.List(Count) List1.Selected(Count) = 0

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 28: VB12

Next Count List_Refresh List1, List2 List1.Clear End SelectEnd Sub

' Special Subroutine to move selected items from one listbox to anotherPublic Sub List_Refresh(SourceList As Control, TargetList As Control) Dim N As Integer Dim I As Integer ReDim Remove(0 To SourceList.ListCount - 1) As Boolean 'Items to remove For N = 0 To (SourceList.ListCount - 1) ' If selected, then , add to Target List If SourceList.Selected(N) = True Then TargetList.AddItem SourceList.List(N) Remove(N) = True ' Sets item for removal from Source list End If Next N

Dim C As Integer ' Counts how many have been removed C = 0 For N = 0 To UBound(Remove) If Remove(N) Then SourceList.RemoveItem N - C C = C + 1 End If Next N

For I = 0 To (SourceList.ListCount - 1) ' Reset Selected Flags and reset SourceList.Selected(I) = False Next I SourceList.Refresh TargetList.RefreshEnd Sub

"This method is meant to work best when the multi-select feature of the listboxes is enabled"

Check a DOB against a valid age

Description: This function checks a DOB against a valid age.Returns 'True' if the DOB is valid for the specified age.Returns 'False' if the DOB is not valid for the specified age.I've used this in CGI programs that need DOB validation.Function CheckDOB(TestDOB As String, ValidAGE As Integer) As Boolean Dim TmpInt As Long

TmpInt = DateDiff("d", CDate(TestDOB), Now)

If TmpInt < (ValidAGE * 365.25) Then CheckDOB = False Else CheckDOB = True End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 29: VB12

End FunctionTip supplied by James Johnston [email protected]

Tells whether a number is even or odd.Returns 'True' if even.Returns 'False' if odd.

Function IsEven(TestInt As Integer) As Boolean Dim TestValues As String, TmpChar As String, Answer As Integer

TestValues = "02468" TmpChar = Right$(Trim(Str$(TestInt)), 1) Answer = InStr(1, TestValues, TmpChar)

IsEven = Answer

End FunctionTip supplied by James Johnston [email protected]

Accessing Databases

This tip is on accessing databases. For performing an operation in every record of a Table or RecordSet(for example you could want to update some fields, or retrieve some information), generally this code isused.Do ... ... MyDynaset.MoveNextLoop Until MyDynaset.EOF

Bat if you use this code

Dim k As Long, j As Long

MyDynaset.MoveLastj = MyDynaset.RecordCountMyDynaset.MoveFirst

For k = 1 to j ... ... MyDynaset.MoveNextNextyou should notice is 30% speed increase from the first code. I tried this code with a MDB file with 17000records, and with a MDB file with 500 records. They both work well. The reason? Of course because thesecond code does not check the EOF condition every iteration (even if it must go to the last record andthen to the first record)! Maybe, if the recordset is small you may not notice any improvement, but in thiscase, processing time is short anyway. I found this code does not improve processing time in Delphi. Ithink it's because Delphi EXE is compiled and not p-code.

1 Why does CommonDialog control show error "No Fonts Installed" when ShowFont method is called ?The possible reason could be invalid value assignment for Flags property of CommonDialog Control.

Try assigning cdlCFBoth to Flags property. This will inform the Control to use the installed fonts.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 30: VB12

2 What's the alternate way of connecting to database using Recordset without Connection object [ADO]?

Dear Ravi, It's possible to avoid use of a separate connection object by passing ConnectString toActiveConnection property of the Recordset Object. But this may not help you in reducing the resourceusage.

3 How can i add the application to SysTray in windows ? Can you please help me out ? Dear Hansal, It's possible to add your VB form to System Tray in 32-bit windows. Yu can fidn the

code for this with detailed explanation in the 'Downloads Section' of VB Forum on this site. Thank you foryour query.

4 Is it possible to create our own setup programs (customized) for installing VB Applications ? If so howcan we do it ? Do we need to know VC++ or SDK ?

Hi Anwar and Ramesh, You need to know only VB, Application Package and Deployment Wizard forpreparing a customized installation program. A VB App Installer package will have two major filesfirstly, setup.exe and secondly, setup1.exe. The former one installs VB Runtime Environment and thelater installs the actual application. So it's always possible to modify (customize) Setup1.exe file. It'snothing but a VB Project.

5 Sir as we will be using forms with similar properties like BorderStyle, WindowState, StartUp position,Font, BackColor, ForeColor and sometimes even startup code, Can't we make templates and use this formas a VB Form ? [ Srinath, Sripad, Manjunath, Harry and Monica ]

Hello, The query sent by all of you was very similar. It'll be very usefull while developing bigapplications. It's possible to create your own templates. What all you ahve to do is, Open a new form setall the properties add any code required and save it in <VB-HOME>\Template\Forms\ Folder. After thisyou can see the new form in the VB Add Form Dialog itself. Thank you.

6 Is it possible to allow the user to Cut or Copy the contents of a password field (Text Box) ?Hi Again Anwar, Well by default you are not allowed to copy or cut the contents of a password field

but it's possible to provide this feature by writing few lines of code in the KeyDown or KeyUp Events ofthe password field. The following code demonstrates the same. [ To run the following code open aStandardEXE Project and add a TextBoxby name Text1 and set it's PasswordChar field to * or # etc... ]Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer) 'For Cut [ Ctrl + X ] If Shift =vbCtrlMask And KeyCode = vbKeyX Then Clipboard.SetText Text1.Text Text1.Text = "" End If 'ForCopy [ Ctrl + C ] If Shift = vbCtrlMask And KeyCode = vbKeyC Then Clipboard.SetText Text1.TextEnd If End Sub

7 Sir, Actual Problem that i have is Can we Create control like DataGrid which containscombobox,CheckBox. Means when we call addnew method then user must be able to select apprppriatetype from combobox as well as check for his status with check box. [ Mahesh Shinde<mailto:[email protected]> ]

Dear Mahesh, What i understood from your query is, you wanna integrate ComboBox and CheckBoxsort of controls with DataGrid so the user can choose a value from a list or check rather than typing. It'spossible. Either you can create a new control or soemtiems you can prepare a floating control. Anyways isuggest yout o gor for the later as the former one would take more time and you need to be carefull whiledesigning such a control as it may kill available resources.

8 I am doing a final year project at the mement and wan't to know how to control the Com1(or 2) portsusing VB, to Tx & Rx data from a hand unit. any suggestions welcome. [ Sweeney<mailto:[email protected]> ]

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 31: VB12

Dear Sweeney, It's very much possible to control the Communication prots from a VB application.Please download THIS <zipz/Q_8_VID103.zip> zip and go through, it may help you.

9 sir i would like to know the code to disable the default rightclick menu that pops up when we right clikon a text box (when appl is running) except for this all other aspects for the textbox must be enabled I wasunable to find any such refrence in the site. [ Deepa Iyer <mailto:[email protected]> ]

Hi Deepa, The best possible way of doing it is using SubClassing. You have to use few APIs for this.Please download THIS <zipz/Q_9_VID104.zip> file. It has both the source code and some docs aboutsubclassing. Hope this will solve your problem.

10. How do you speed up VB programs?This is a really big topic but this is going to be, at first at least, just a small section. Four things that canoften be a proven speeder upper of your program are:

Go to the Tools|Custom Controls menu choice. Remove ALL check marks or all that it lets you. Then goto the Tolls|Reference menu choice. Remove all of these it lets you. You should be left with most of thecontrols your programs need. Most of the rest of the controls your program might need are probably inWindows Common Controls(Go back to Tools|Custom Controls and check this if you need this). Thismakes a HUGE difference in many parts of your program. Loading it when run and when edited in VB isfaster. The needed files list in the Setup Wizard is cut in half almost.

Use Labels instead of TextBoxes, unless the user needs to type into the TextBox. If you like the look of theTextBox you can reproduce it by setting a Labels border to Single.

Use control arrays for any related controls, especially with Label controls that just display text and donothing else. Also this works really well with Option Controls contained in a Frame.

Unless you have pictures that are updated often, you can set the Autoredraw to False and as long as youplaced controls correctly, no overlapping, set the Clip Controls option to False.

11. How to play a WAV file in VB ?

This example shows how to play a WAV file in VB. It requires one declaration (API) and one SUB. Thedeclaration looks like this: ' Declare Function sndPlaySound Lib "MMSYSTEM" (ByVal lpWavName$, ByVal Flags%) As IntegerNext, create a SUB to actually handle the playing of the WAV file. We'll call it PlaySound. It requires oneargument to be passed to it. The argument filename is the name of the WAV file to play.Sub PlaySound (FileName As String) Dim x% x% = sndPlaySound(FileName, 1)End SubFinally, place a command button or some other control on the form and place the following code in it'sclick event procedure. We'll use TADA.WAV for the sound to play, but it could just as easily be any WAVfile you like.Command1_Click PlaySound ("tada.wav")End SubFinally, just run the program and click the button!

12. Detecting Previous Instance of Form ?Ans.This routine will prevent two copies of your program from running at the same time. It consists of aFunction that determines if another instance is already running and activates it if it is. The Sub

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 32: VB12

(Form_Load()) calls this function and closes the program if there is another instance of the programrunning.Function AnotherInstance () As Integer Dim AppTitle$ If App.PrevInstance Then ' Hold the title of the application (title bar caption) AppTitle$ = App.Title ' Change our application title App.Title = "No longer want this app running..." ' Activate the previous instance AppActivate AppTitle$ ' Let calling procedure know another instance was detected AnotherInstance = True Else ' Let calling procedure know another instance was NOT detected AnotherInstance = False End IfEnd Function

Sub Form_Load () ' Don't want two copies of the program running at the same time If AnotherInstance() Then End ' Note: that this routine will not work if the application's title changes ' (showing file names in the title bar for example).End Sub

13. How to Extract Numer ical Values from Text Str ings ?Ans . The purpose of this routine is to take a string of text (such as with a textbox) and extract anumerical value from it. let's say that you have a textbox in which people enter dollar amounts. Manyusers are likely to enter something such as "$ 4,335.49" and expect calculations to be performed on it. Thetrouble is, the value of that string is 0 (zero), not 4335.49!Using the following function, a person would actually be able to enter a string like "$4,335.49" or even"4335.49 dollars" and still have the value returned as 4335.49. The function shown below calledPurgeNumericInput requires one argument. That argument is a string containing numbers with or withoutspecial characters. Look at the function below.Function PurgeNumericInput (StringVal As Variant) As Variant On Local Error Resume Next Dim x As Integer Dim WorkString As String

If Len(Trim(StringVal)) = 0 Then Exit Function ' this is an empty string For x = 1 To Len(StringVal) Select Case Mid(StringVal, x, 1) Case "0" To "9", "." 'Is this character a number or decimal? WorkString = WorkString + Mid(StringVal, x, 1) ' Add it to the string being built End Select Next x PurgeNumericInput = WorkString 'Return the purged string (containing only numbers and decimalsEnd FunctionYou then just need to call the function passing a string argument to it. An example is shown below.Sub Command1_Click Dim NewString as Variant

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 33: VB12

NewString = PurgeNumericInput("$44Embedded letters and spaces 33 a few more pieces of garbage.9") If Val(NewString) <>0 Then MsgBox "The Value is: " & NewString Else MsgBox "The Value is ZERO or non-numeric" End IfEnd SubNotice how much alphanumeric garbage was placed in the string argument. However, the returned valueshould be 4433.9! Two questions might arise when using this type of example.#1 - What if the string was "0"? This could be determined by checking the length of the string (variant)returned. If the user entered a "0" then the length of the string would be > 0.#2 - What if the string contains more than one decimal? You could use INSTR to test for the number ofdecimals. However, chances are, if the user entered more than one decimal you might better have them re-enter that field again anyway. <sly smile>

14. How to Create Multi colored Forms in VB without using API ?Ans Although using the API is a nice way to create multi-colored forms, there might be a reason why youwould wish to create one without using the API. To use the example shown below, place the SUB in amodule (* .BAS). The routine requires several parameters to be passed to it. They are:

• FormName - Used to indicate which form is to be colored• Orientation% - Top to bottom or right to left painting effect• RStart% - (0-255) value for Red• GStart% - (0-255) value for Green• BStart% - (0-255) value for Blue• RInc% - Amount to increment or decrement for Red• GInc% - Amount to increment or decrement for Green• BInc% - Amount to increment or decrement for Blue

Sub PaintForm (FormName As Form, Orientation%, RStart%, GStart%, BStart%, RInc%, GInc%,BInc%)' This routine does NOT use API calls On Error Resume Next Dim x As Integer, y As Integer, z As Integer, Cycles As Integer Dim R%, G%, B% R% = RStart%: G% = GStart%: B% = BStart% ' Dividing the form into 100 equal parts If Orientation% = 0 Then Cycles = FormName.ScaleHeight \ 100 Else Cycles = FormName.ScaleWidth \ 100 End If For z = 1 To 100 x = x + 1 Select Case Orientation Case 0: 'Top to Bottom If x > FormName.ScaleHeight Then Exit For FormName.Line (0, x)-(FormName.Width, x + Cycles - 1), RGB(R%, G%, B%), BF Case 1: 'Left to Right If x > FormName.ScaleWidth Then Exit For FormName.Line (x, 0)-(x + Cycles - 1, FormName.Height), RGB(R%, G%, B%), BF End Select x = x + Cycles R% = R% + RInc%: G% = G% + GInc%: B% = B% + BInc%

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 34: VB12

If R% > 255 Then R% = 255 If R% < 0 Then R% = 0 If G% > 255 Then G% = 255 If G% < 0 Then G% = 0 If B% > 255 Then B% = 255 If B% < 0 Then B% = 0 Next zEnd SubTo paint a form call the PaintForm procedure as follows:PaintForm Me, 1, 100, 0, 255, 1, 0, -1Experiment with the parameters and see what you can come up with. Keep the values for the incrementinglow so as to create a smooth transition, whether they are negative or positive numbers.

15. I would like to create masks for date and time input. I have heard ofthe MaskedEdit control but don`t know how to use it.Ans. Keyword: MaskedBox control, Mask property.

Example: To input a date in a MaskedEditBox, set its mask to "##/##/####". Whenyou run the app, the box will show "__/__/____" and you will be able to typenumbers in its prompt area.

16. I am wr iting a VB5 program to inter face with a MS Accessdatabase...it will add and delete records and scroll through all therecords cur rently entered. I need to be able to add a Find function to thisapplication. I tr ied the FindFirst and FindNext methods but...it didn`twork. I need it to display the record that matches the given searchstr ing.

A: You want to Search the Given data in a Table...Let me give you anexample for this. Suppose You want to Search for CustomerName inCustomer Table of CustomerDetails Database. The text you want tosearch is in "Text1.Text" box.

Dim VSearch as String

VSearch = "CustomerName="+Text1.TextCustomerDetails.Recordset.FindFirst VSearch

'This is all you have to do to check that'your search is succesful use NoMatch Property

ustomerDetails.Recordset.Nomatch = True' Not FoundElse "Record is Found "

Yogesh

A: The following is from an early program of mine.Today I use SQL and do not use the data controlif possible. But this works:

Dim sBookMk As String, sTmp As String

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 35: VB12

sBookMk = Data1.Recordset.BookmarkTmp = "Name >= " & Chr$(34) & _ txtSeek.Text & Chr$(34)'Was one line.Data1.Recordset.FindFirst sTmpIf Data1.Recordset.NoMatch ThenData1.Recordset.Bookmark = sBookMkEnd If

The number one problem with FindNext, etc. methods and SQL is inhandling the quotes. Note the Chr$(34)`s. They are quotation marks.Beyond that, note that the routine cleans up after itself by checkingfor a match. If no match, the data control`s recordset is set back tothe record that was current prior to the FindNext.

Ans: In an inventory database I have I need to be able to look up itemsby number. This must be done so entering a number of 35 will finditem 35, but not item 535. In case it would help here is the codeI use from my access module.

Function Find_Record_By_Item#()Dim Notice As StringDim Msg As StringDim Buttons As IntegerDim Title As StringDim Number As StringDim Number2 As Integerstart:Msg = "Enter an item number to look up and press enter." _& Chr(13) & Chr(13) & "To cancel this operation press escape."Title = "Item Number Look up"Number = InputBox(Msg, Title)If Number <> "" ThenDoCmd.FindRecord Number, acEntire, False, acSearchAll, True, acAll, TrueScreen.ActiveForm![txtItem_Number].SetFocusNumber2 = Screen.ActiveForm![txtItem_Number].TextIf Number <> Number2 ThenMsg = "The item number you entered was not found." & Chr(13) _& "Please enter another one."Title = "Invalid Item Number"Buttons = 48Notice = MsgBox(Msg, Buttons, Title)GoTo startEnd IfElseScreen.ActiveForm![txtItem_Number].SetFocusEnd IfIf Screen.ActiveForm![txtItem_Number].Locked = True ThenScreen.ActiveForm![txtDate_of_Sale].SetFocusEnd IfEnd Function

The last If allows for immediate data entry after lookupon the sales form where the item number, description, and

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 36: VB12

asking price fields are looked (They can only be changedon the items form.). Chr(13) represents a carriage return.

17. Forms with Scrollbars?The problem I am facing is this : I am trying to create a form with a height greater than the current screenheight, and I am trying to incorporate vertical scrollbars to navigate up and down in that form. I have noidea how to do it. Any help would be appreciated.

A. Add a picture box, and then the scroll box to the form. Have the scroll bar move the picture box up anddown on the form. Put all of the controls on the "scrollable form" inside the picture box. Make sure thepicture box has no border.

18. How do I make a Combo box drop down whenthe control first gets focus?

A. One way that this can be done in VB5 is with the SendKeys command as follows:

'Put this in Combo1_GotFocus:

If Combo1.ListIndex = -1 ThenSendKeys "{ F4} { Down} "ElseSendKeys "{ F4} "End If

This will make it dropdown and select first item if nothing is selected or just drop down if there is an itemalready selected.

19. How to activate cancel button in dialog box?

How do I assign the cancel property to the cancel button of a simple dialog box? I`ve written a macro inExcel using VB and use dialog box inputs to get user data. However, hitting the cancel button duringdata entry has no effect.

A. What you have to do is set CancelError = True

This means that if the user presses Cancel it causes an error - so then you set up an error trap to do whatever you want when the error happens. Look in the help file to get the exact syntax but it is something likethis:'Pseudo codeon error goto errortrap ... ... ...'all your stuff here ... ... ...exit suberrortrap:if err=32755 then'that might not be the right value, you can look up the error'codes in the help file.end ifend sub

20. . I need to know how to pass var iables between two forms.

A. There are two ways to accomplish this:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 37: VB12

1. Declare your variables needed in both forms as global in a module. This will make them accessable for all. 2. The other way is to prefix a variable name with its form name: Form2.Label1.Caption = Form1.List1.List(List1.ListIndex) This example displays in Form2, Label1, the item selected in a Listbox on Form1.

21. I `m trying to wr ite some code where clicking a radio button on form#1 makesa command button visible on form #2. I know how to do this within one form, but I don`t know how to dothis with two forms.

A. This is an easy one. You just have to include Form2`s name in front of the button`s name. Example:

1.)Create two forms(Form1 and Form2)2.)On Form1 place two option buttons(Option1 and Option2)3.)On Form2 place one command button(Command1)

'code for Form1Private Sub Form_Load()Form2.Show 'Show Form2 along w/Form1End Sub

Private Sub Option1_ClickForm2.Command1.visible = True 'Show button. See?End Sub

Private Sub Option2_ClickForm2.Command1.Visible = False 'Hide button.End Sub

22. How To: Capture Keyboard Input

Ans : Keywords to see in on-line help: KeyPreview property, KeyDown, KeyUpand KeyPress events, ActiveControl property.

If you need to capture a user`s keyboard input _before_ the keystrokereaches any of the controls mounted on a form, set your form'sKeyPreview property to True, and process each keystroke in theform`s KeyDown, KeyUp or KeyPress events. Use the KeyPress eventfor regular alphanumeric (ANSI) keystrokes and the KeyDown or KeyUpevents for all other keys (Escape, Backspace, Enter, Arrow keys,Function Keys, etc.). A simple example:

Private Sub Form_KeyPress(KeyAscii As Integer)

If ActiveControl.Name = "txtName" Then 'If txtName has the focus...If KeyAscii < 65 Or KeyAscii > 90 Then 'If keystroke is NOT a capital letter.If KeyAscii >=97 And KeyAscii <=122 Then'If lower case...KeyAcsii = (KeyAscii Or 32) 'Convert to upper case.ElseKeyAscii = 0 'Set keystroke to zero.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 38: VB12

End IfEnd If

The above is a brief example of the control your code can have overkeyboard input. The code fragment simply filters out any charactersthat are not upper case. If the character received is lower case, it isconverted to caps, otherwise the character is zeroed out. Setting thekeystroke value to zero will be interpreted by most controls as a nullcharacter and will therefore be ignored. You can also set thekeystroke to some other default value depending on the controlreceiving the keystroke.

New TipsDollar sign Functions--what are they?

Ever wonder about those functions ending in a dollar sign? If you are running VB5 or VB6, you might noteven see them mentioned in VB Help.

In VB, there are a number of functions that have a dollar sign version---such as Left$, Right$ and Case$

What's the difference between the functions Left$ and Left?

For those of you not familiar with functions, functions return a value to the procedure that calls them.This return value can be of a particular data type, and dollar sign functions return a value of type String.Thenon-dollar sign versions return a Variant Data Type.

Which one should you choose to use?

Dollar sign functions run faster than non dollar sign functions, so in general, it's a good choice to usethem.

Is there ever a reason to use the non-dollar sign function?

Yes---if there's a possibility that the function will encounter a Null character in its argument string, youneed to use the non-dollar sign version--otherwise the function will bomb. For instance, in this code

Form1.Print Left(string1, 1)Form1.Print Left$(string1, 1)

both Left and Left$ will return the left-most character of the string. However, if string1 contains a Nullcharacter, Left$ will bomb---however, Left will work fine.

Trying to compile a Project using the VB Learning Edition?

You'll need to purchase either the Visual Basic Standard, Professional or Enterprise edition in order tocompile your program into an executable.

'-------------------------------------------

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 39: VB12

Your compiled program won't run on a fr iend's PC

You probably gave your friend just the compiled executable file.

Visual Basic programs need to have the Visual Basic runtime DLL installed on the PC also---plus someother support files.

The easiest way to do this is to run the Package and Deployment Wizard in Visual Basic to create a Setuppackage.

Then all you need to do is give the diskette(s) to your friend, and have them run the Setup program foundon Disk 1---the same they would do for any other Windows program.

This way both your executable, and the Visual Basic runtime DLL and support files are installed.

'-------------------------------------------

Looking for a free version of VB?

Microsoft made a free version of VB5 called the Control Creation Edition available for download fromtheir website.There is no free version of Visual Basic 6 available from Microsoft. However, there are several VisualBasic books (including my first book, Learn to Program with Visual Basic 6) on the market that comewiththe Visual Basic Working Model Edition--which is a surprisingly full featured version of Visual Basic(no,you can't compile programs with it).These tips were extracted from the June 2000 issue of the Visual Basic Explorernewsletter and were submitted by John Smiley. Be sure to check out John's othertutorials in the tutorials section or check out his website here <http://www.johnsmiley.com>.

You can direct any questions, comments or suggestions to the VB Forums<http://www.vbexplorer.com/q&aform.asp> sectionof this site. Many of the more interesting or frequently asked questions willend up in one of our newsletter issues.

'-------------------------------------------

Where have you gone Crystal Repor ts?

Crystal Reports, the leading third party Report Writer for Visual Basic, was previously packaged with VBin versions 4 and 5 and appeared as an Add-in off of the Visual Basic menu.

VB6 users were disappointed to find that Crystal Reports apparently was not shipped with VB6---mostlikely, it was believe, because Microsoft decided to include a Report Writer of its own called the MicrosoftData Report designer.

For those of you still yearning for Crystal Reports, take heart--you can still find it on your Visual Basicinstallation CD-ROM, provided, that is, you purchase Visual Basic Pro or Enterprise.

To find it, look in the

\Common\Tools\CryReports

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 40: VB12

folder on your installation CD.'-------------------------------------------

Access Key for a Textbox

Most Visual Basic programmers are familiar with how to designate an access or hot key for a CommandButton. An Access key allows the user to `click` on the control by pressing the Alternate Key plus a letter.

For instance, if you have a Command Button whose caption is OK, to designate a hot key combination ofAlternate+O for the Command Button, you specify

&OK

as the Caption property for the Command Button.

But what a shortcut to get to a Textbox?

The user can click on the textbox or tab to it, but wouldn't it be great to be able to get to a Textbox bypressing the Alternate key plus a character?

Well, as it turns out, there is.

The secret is to place a label control next to a textbox, and then designate a hot key combination for thelabel control using the ampersand character in the Caption property of the label control.

For instance, if

you have a textbox sitting next to a label control whose Caption Property is &Name, if the user pressesAlternate+N, focus will move to the textbox adjacent to the label control.

Just one word of warning. In order for this to work, the Textbox's TabIndex property must be immediatelyafter the TabIndex Property of the Label Control. If the Label Control's TabIndex property is 15, forinstance, the Textbox must be 16.

'-------------------------------------------

Textbox selection goes away

Have you noticed that if the user selects text in a textbox, and then moves focus off of the textbox, that thetext is no longer selected.

This is because the HideSelect property of the textbox is by default set to True.

If you would prefer to keep the text selected when the user moves `off` of the textbox, then just set theHideSelect property of the Textbox to False.

'-------------------------------------------

Password Char

Have a textbox into which you want the user to type an entry, but don't want anyone looking over theirshoulder to see it.

Just set the PasswordChar Property of the textbox to something other than its default blank character.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 41: VB12

For instance, if you set the PasswordChar Property to an asterisk(* ), then whatever the user enters into theTextbox will appear as asterisks.

'-------------------------------------------

The Click event requires both the Mouse Down and Mouse Up over thecontrol

Just a reminder that in order for the Click event procedure of a control to take place, the user must bothclick and then release the mouse button over the control. If, after clicking the mouse over the control theythen move it over the form or over another control before releasing it, the click event procedure nevertakes place.

'-------------------------------------------

Entr ies in a L istbox

Many beginners are confounded with the List Property of a Listbox, which is where the programmer can,at design time, place items that are to appear in a Listbox.

Why are they confounded?

Because when they type an item into the Listbox, invariably they hit the ENTER key, and the ListProperty in the Properties Window closes. They select it again, make a second entry, and then hit ENTERagain. Once again, the List property closes. This continues on and on until they have finished adding allof the items (experienced programmers use the AddItem Method of the Listbox at runtime.).

If you want to add items to a Listbox at design time using the List property, after making your first entry,type the

Ctrl+N

combination instead of the hitting the ENTER key. This will advance the carriage return to the next linein the List property, and enable you to more quickly add the items to the Listbox.

Working with the TrayThe Windows 95 tray (recessed area on the right side of taskbar) provides an easy way forutility and notification programs to run, with out cluttering up the taskbar. Examples ofsuch programs include: the volume control (if you have a sound card), the FlexiCDcontrol, and the Resource Meter. Don't you wish you could create applications downthere, too? Oh, but you can, and it's easier that you think!Laying Out a PlanBefore designing a tray-based application, you must first decide if putting your application there makessense. Obviously, putting a word processor or spreadsheet there would be a bad idea, but a notificationprogram of some sort would be useful. For example. if you were writing a PIM (personal informationmanager), you could make an alarm clock to go into the tray that would notify the user about upcomingappointments.

Each icon in the tray is 16 by 16 pixels large -- the same as a control menu icon. Any icon can be used,but if you use a 32 by 32 pixel icon, it will be re-sized to fit the space. If you want to create a separate icon

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 42: VB12

for this, use an icon editor that supports multiple resolution icons. The ImageEdit program on the VisualBasic 4.0 CD does this.You will also need to take under consideration a few other details: every icon needs a menu. If all it doesis exit the program, that's fine. When users right click on the icon, they expect a menu -- give them one.You will also need some sort of ToolTip for your icon. Keep it simple and to the point, but not cryptic. Wewill discuss how to implement menus and ToolTips later in this article.Welcome to the Thunder Filling StationThe Thunder Filling Station (Thunder was the code name for VB, get it?) is a small demo the shows howto implement icons in the tray. It acts as a gas station, that will allow you to fuel you car from the taskbar(if it were only real!)Note: The code used in this article is available in the Toolbox's<http://www.netins.net/showcase/legend/vb/> CodeVault. The file UI-0596.ZIP is a Visual Basic 4.0 (32-bit) project that contains a sample application that fully demonstrates the techniques in this article.The following goes in the General, Declarations section. It sets all of the constants and declarations areneeded by the program.Option Explicit

' Used to detect clicking on the iconPrivate Const WM_LBUTTONDBLCLK = &H203Private Const WM_RBUTTONUP = &H205

' Used to control the iconPrivate Const NIM_ADD = &H0Private Const NIM_MODIFY = &H1Private Const NIF_MESSAGE = &H1Private Const NIM_DELETE = &H2Private Const NIF_ICON = &H2Private Const NIF_TIP = &H4

' Used as the ID of the call back messagePrivate Const WM_MOUSEMOVE = &H200

Private Declare Function Shell_NotifyIcon Lib "shell32" Alias"Shell_NotifyIconA" (ByVal dwMessage As Long, pnid As NOTIFYICONDATA)As Boolean

' Used by Shell_NotifyIconPrivate Type NOTIFYICONDATA cbSize As Long hWnd As Long uId As Long uFlags As Long ucallbackMessage As Long hIcon As Long szTip As String * 64End Type

Dim TrayIcon As NOTIFYICONDATAThe code that follows is needed in the Form_Load event.Private Sub Form_Load() TrayIcon.cbSize = Len(TrayIcon) ' Handle of the window used to handle messages TrayIcon.hWnd = Me.hWnd ' ID code of the icon

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 43: VB12

TrayIcon.uId = vbNull ' Flags TrayIcon.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE ' ID of the call back message TrayIcon.ucallbackMessage = WM_MOUSEMOVE ' The icon TrayIcon.hIcon = imgIcon.Picture ' The Tooltip for the icon TrayIcon.szTip = "Free 16-oz fountain pop with gas purchace!" & Chr$(0)

' Add icon to the tray Call Shell_NotifyIcon(NIM_ADD, TrayIcon)

' Don't let application appear in the Windows task list App.TaskVisible = False

' Hide form on start-up Me.HideEnd SubThe first seven statements sets the parameters for the Shell_NotifyIcon event. Most of these can be usedas-is in your applications, but you may wish to change TrayIcon.hIcon, which sets the actual icon that isdisplayed, and TrayIcon.szTip, which is the ToolTip that appears when the user leaves the cursor over theicon. By calling Shell_NotifyIcon, we place the icon in the tray. Finally, we hide the application from thetask list using the App object, and we hide the form on start up.Now that we have the icon in tray, we need to be able to handle it once it's there. We do that using thenext chunk of code. It is needed in the MouseMove event of the controlling form, or other control youspecified in Shell_NotifyIcon.hWnd:Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) Static Message As Long Static RR As Boolean

Message = X / Screen.TwipsPerPixelX

If RR = False Then RR = True Select Case Message ' Left double click (This should bring up a dialog box) Case WM_LBUTTONDBLCLK Me.Show ' Right button up (This should bring up a menu) Case WM_RBUTTONUP Me.PopupMenu mnuPump End Select RR = False End IfEnd SubThis looks for one of two things. If the user double clicks on the icon, it displays it's form. If they rightclick on the icon, a popup menu is displayed that gives the user a list of options. The menu needs to resideon the controlling form, but the top-most level must be hidden.Ready to go? Before ending your program, you should always remove the icon, therefore, place this inQueryUnload to remove the icon:Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) TrayIcon.cbSize = Len(TrayIcon) TrayIcon.hWnd = Me.hWnd

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 44: VB12

TrayIcon.uId = vbNull 'Remove icon Call Shell_NotifyIcon(NIM_DELETE, TrayIcon)End SubLike other notification programs, your VB application can also place itself in the Windows 95 tray. All ittakes is a few chunks of code. If your are still having problems, be sure to download the code!

Creating a Toolbar The toolbar (also called a ribbon or control bar) has become a standard feature inmany Windows-based applications. A toolbar provides quick access to the most frequentlyused menu commands in an application. Creating a toolbar is easy and convenient usingthe toolbar control, which is available with the Professional and Enterprise editions ofVisual Basic. If you are using the Learning Edition of Visual Basic, you can createtoolbars manually as described in "Negotiating Menu and Toolbar Appearance" later inthis chapter.

The following example demonstrates creating a toolbar for an MDI application; theprocedure for creating a toolbar on a standard form is basically the same.

To manually create a toolbar

1. Place a picture box on the MDI form.

The width of the picture box automatically stretches to fill the width of the MDIform's workspace. The workspace is the area inside a form's borders, not includingthe title bar, menu bar, or any toolbars, status bars, or scroll bars that may be onthe form.

Note You can place only those controls that support the Align property directlyon an MDI form (the picture box is the only standard control that supports thisproperty).

2. Inside the picture box, place any controls you want to display on the toolbar.

Typically, you create buttons for the toolbar using command buttons or imagecontrols. To add a control inside a picture box, click the control button in thetoolbox, and then draw it inside the picture box.

Note When an MDI form contains a picture box, the internal area of the MDIform does not include the area of the picture box. For example, the ScaleHeightproperty of the MDI form returns the internal height of the MDI form, which doesnot include the height of the picture box.

3. Set design-time properties.

One advantage of using a toolbar is that you can present the user with a graphicalrepresentation of a command. The image control is a good choice as a toolbarbutton because you can use it to display a bitmap. Set its Picture property at designtime to display a bitmap; this provides the user with a visual cue of the commandperformed when the button is clicked. You can also use ToolTips, which display

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 45: VB12

the name of the toolbar button when a user rests the mouse pointer over a button,by setting the ToolTipText property for the button.

4. Write code.

Because toolbar buttons are frequently used to provide easy access to othercommands, most of the time you call other procedures, such as a correspondingmenu command, from within each button's Click event.

Tip You can use controls that are invisible at run time (such as the timer control) with anMDI form without displaying a toolbar. To do this, place a picture box on the MDI form,place the control in the picture box, and set the picture box's Visible property to False.

Writing Code for Toolbars

Toolbars are used to provide the user with a quick way to access some of theapplication's commands. There are now three places in the MDI NotePad sampleapplication where the user can request a new file:

• On the MDI form (New on the MDI form File menu)

• On the child form (New on the child form File menu)

• On the toolbar (File New button)

Rather than duplicate this code three times, you can take the original code from the childform's mnuFileNew_Click event and place it in a public procedure in the child form. Youcan call this procedure from any of the preceding event procedures. Here's an example:

' This module is in a public procedure.Public Sub FileNew () Dim frmNewPad As New frmNotePad frmNewPad.ShowEnd Sub

' The user chooses New on the child form File menu.Private Sub mnuchildFileNew_Click () FileNewEnd Sub

' The user chooses New on the MDI form File menu.Private Sub mnumdiFileNew_Click () frmNotePad.FileNewEnd Sub

' The user clicks the File New button on the toolbar.Private Sub btnFileNew_Click () frmNotePad.FileNewEnd Sub

Visual Basic Concepts

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 46: VB12

Adding an Event to the ShapeLabel Control

It’s important to distinguish between the events received by your UserControl object (orby the controls it contains) and the events your control raises. Events your controlreceives are opportunities for you to do something interesting; events your control raisesprovide opportunities for the developer who uses your control to do somethinginteresting.

There are many events that might be of interest to the user of the ShapeLabel control. TheVisual Basic Label control raises a Click event, and ShapeLabel is just a fancy label, so thefollowing procedure will add a Click event. To make the event more interesting, it will beraised only if the user clicks on the oval background.

Being compatible with other controls of the same type is an important reason to add aparticular event to your control. Other criteria for choosing what events to raise can befound in "Raising Events from Controls," in "Building ActiveX Controls."

Note This topic is part of a series that walks you through creating a sample ActiveXcontrol. It begins with the topic Creating an ActiveX Control.

To add a Click event to the ShapeLabel control

1. In the Project Explorer window, click ShapeLabel to select it, then press F7 or click the Codebutton on the Project Explorer window toolbar, to open the Code window.

2. In the Object box, select (General). In the Procedure box, select (Declarations) to positionyourself at the top of the code module. Add the following code:

3. Option Explicit4. ' Declare a public Click event with no arguments.5. Public Event Click()

6. In the Object box, select lblCaption. In the Procedure box, select the Click event for the labelcontrol. Add the following code to the lblCaption_Click event procedure:

7. Private Sub lblCaption_Click()8. ' Raise a Click event whenever the user clicks9. ' on the label.10. RaiseEvent Click11. End Sub

The code above raises a Click event only if the user clicks on the constituentcontrol lblCaption. It will seem more natural to users to be able to click anywhereon ShapeLabel’s oval background, so the next step shows how to raise the clickevent if the user clicks on the colored oval.

12. In the Object box, select UserControl. In the Procedure box, select the UserControl’sMouseUp event. Add the following code to the UserControl_MouseUp event procedure:

13. Private Sub UserControl_MouseUp(Button As Integer, _14. Shift As Integer, X As Single, Y As Single)15. ' Raise a Click event only if the color of the

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 47: VB12

16. ' point that was clicked on matches the color17. ' of the Shape control. Ignore clicks that are18. ' outside the oval.19. If Point(X, Y) = shpBack.FillColor Then20. RaiseEvent Click21. End If22. End Sub

Determining whether an event occurred in a particular location is called hit testing.

You might expect to put the hit test code in the shpBack_Click event procedure,because shpBack is always resized to cover the entire surface of the ShapeLabelcontrol. However, Shape controls don’t receive Click events. Instead, the Clickevent is received by the object that contains the Shape — in this case, theUserControl object.

"Drawing Your Control," in "Building ActiveX Controls," discusses the use oftransparent backgrounds to create irregularly shaped controls.

23. In the Project Explorer window, click Form1 to select it, then press F7 or click the Code buttonon the Project Explorer window toolbar, to open the Code window.

24. In the Object box, select one of the ShapeLabel controls you added to Form1. In the Procedurebox, select the Click event.

Note If the Click event does not appear, make sure the ShapeLabel designer isclosed.

Add the following code to the ShapeLabel1_Click event procedure:

Private Sub ShapeLabel1_Click() MsgBox "Thanks for clicking! My caption is: " _ & ShapeLabel1.CaptionEnd Sub

Note If the ShapeLabel you selected is not named ShapeLabel1, use theappropriate name when entering the code above.

You can click the arrow on the Procedure box to view all of the events for theShapeLabel control. In addition to your Click event, there are four events —DragDrop, DragOver, GotFocus, and LostFocus — that are automaticallyprovided for you by the container, Form1.

25. On the toolbar, click the Star t button, or press CTRL+F5 to run TestCtlDemo. Try clickingvarious places on the form and on the ShapeLabel control, to verify that the Click event is beingraised only when you click inside the oval background.

26. There’s a subtle bug in the hit testing for ShapeLabel’s click event. To see this, press the mousebutton while the mouse pointer is in the lower half of the red oval. Holding the mouse button

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 48: VB12

down, carefully move the mouse pointer until the tip of the arrow is on the white text ofShapeLabel’s caption, then release the mouse button. The message box doesn’ t appear!

The lblCaption_Click event procedure doesn’t get executed, because theMouseDown event occurred over the UserControl. Therefore, when the MouseUpevent occurs, it is received by the UserControl — even if the mouse has beenmoved completely off Form1.

The hit test code in the MouseUp event works if the mouse button is released overthe red background that shows through lblCaption’s transparent background, butnot if the button is released over the white foreground color of the text. (If thebutton is released outside ShapeLabel, the Point function returns -1, so releasingthe mouse button over some random red spot will not raise the Click event.)

Fixing this bug is left as an exercise for the reader. (Hint: Moving the hit test to theClick event of the UserControl won’t help, because the Click event doesn’t occurwhen the MouseUp event is over a different object from the MouseDown.)

Visual Basic Concepts

Star ting the Package and Deployment Wizard

The Visual Basic Package and Deployment Wizard makes it easy for you to create thenecessary .cab files and setup programs for your application. Like other wizards, thePackage and Deployment Wizard prompts you for information so that it can create theexact configuration you want.

There are three ways you can start the Package and Deployment Wizard:

• You can run it from within Visual Basic as an add-in. If you run the wizard as an add-in, youmust first set the necessary references in the Add-In Manager to load the wizard. When you usethe wizard as an add-in, Visual Basic assumes that you want to work with the project youcurrently have open. If you want to work with another project, you must either open that projectbefore starting the add-in, or use the wizard as a stand-alone component.

• You can run it as a stand-alone component from outside the development environment. Whenyou run the wizard as a stand-alone component, you are prompted to choose the project on whichyou want to work.

• You can start it in silent mode by launching it from a command prompt. See "Running theWizard in Silent Mode" in this topic for more information.

After you start the wizard, a series of screens prompt you for information about yourproject and let you choose options for the package. Each screen explains how it is to beused, including which information is optional, and what information must be entered

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 49: VB12

before you can move to the next screen. If you find that you need more information on anyscreen, press F1 or click the Help button.

Note You should save and compile your project before running the Package andDeployment Wizard.

In most cases, the Package and Deployment Wizard is all you need to create a packagethat is ready for deployment. However, if you want to customize your packaging processfurther or provide functionality not supported by the Package and Deployment Wizard,you can modify the Setup Toolkit Project.

To start the Package and Deployment Wizard from within Visual Basic

1. Open the project you want to package or deploy using the wizard.

Note If you are working in a project group or have multiple projects loaded,make sure that the project you want to package or deploy is the current projectbefore starting the wizard.

2. Use the Add-In Manager to load the Package and Deployment Wizard, if necessary: Select Add-In Manager from the Add-Ins menu, select Package and Deployment Wizard from the list,then click OK .

3. Select Package and Deployment Wizard from the Add-Ins menu to launch the wizard.

4. On the main screen, select one of the following options:

• If you want to create a standard package, Internet package, or dependency file for theproject, click Package.

• If you want to deploy the project, click Deploy.

• If you want to view, edit, or delete scripts, click Manage Scr ipts.

For an introduction to these options, see "The Package and Deployment Wizard."

5. Proceed through the wizard screens.

To start the Package and Deployment Wizard as a stand-alone component

1. If the project you want to package is open, save it and close Visual Basic.

2. Click the Star t button, and then click Package and Deployment Wizard from the Visual Basicsubmenu.

3. In the Project list on the initial screen, choose the project you want to package.

Note You can click Browse if your project is not in the list.

4. On the main screen, select one of the following options:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 50: VB12

• If you want to create a standard package, Internet package, or dependency file for theproject, click Package.

• If you want to deploy the project, click Deploy.

• If you want to view, edit, or delete scripts, click Manage Scr ipts.

5. Proceed through the wizard screens.

Running the Wizard in Silent Mode

Using scripts, you may package and deploy your project files in silent mode. In silentmode, the wizard runs without your having to attend it to make choices and move throughscreens. The wizard packages and deploys your project using the settings contained in ascript.

Silent mode is especially useful if you are packaging and deploying as part of a batchprocess. For example, early in the development of your project, you may use the Packageand Deployment Wizard to package your project and deploy it to a test location. You canlater create a batch file to perform the same packaging and deployment steps periodicallyas you update your project.

To package and deploy in silent mode

1. Open an MS-DOS prompt.

2. Type the name of the wizard executable, pdcmdln.exe, followed by the path and file name of yourVisual Basic project, and the appropriate command line arguments, as shown in the followingexample:

3. PDCmdLn.exe C:\Project1\Project1.vbp /p "Internet Package"4. /d Deployment1 /l "C:\Project1\Silent Mode.log"

Note You can perform packaging and deployment in a single silent session byspecifying both the /p and the /d arguments, as shown in the example above.Otherwise, use either /p or /d.

Argument Descr iption

/p packagingscript Type /p followed by the name of a previously saved packagingscript to package the project silently according to the specifiedscript.

/d deploymentscript Type /d followed by the name of a previously saved deploymentscript to deploy the project silently according to the specifiedscript.

/l path Specifies that the wizard should store all output from the wizard,such as error messages and success reports, to a file rather thandisplaying them on the screen.

Type /l followed by the path and file name of a file inwhich output should be stored. If the file does not exist,the wizard creates it.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 51: VB12

If you do not choose to log output using this argument,the wizard will display a dialog box to notify whenpackaging or deployment is finished. In order to see thisdialog box, you may minimize or close other windows.

/e path Specifies a path for the project's executable file, if it is differentfrom the path for the project. This argument allows you to packagein silent mode when you are working in a multi-developerenvironment. You might use this option if development andpackaging occur on different computers.

Note Any file or script name that includes spaces should be enclosed in quotation marks,as shown in the example above.

Visual Basic Concepts

Creating Your Own Data Types

You can combine variables of several different types to create user-defined types (knownas structs in the C programming language). User-defined types are useful when you wantto create a single variable that records several related pieces of information.

You create a user-defined type with the Type statement, which must be placed in theDeclarations section of a module. User-defined types can be declared as Private or Publicwith the appropriate keyword. For example:

Private Type MyDataType

-or-

Public Type MyDataType

For example, you could create a user-defined type that records information about acomputer system:

' Declarations (of a standard module).Private Type SystemInfo CPU As Variant Memory As Long VideoColors As Integer Cost As Currency PurchaseDate As VariantEnd Type

Declaring Variables of a User-Defined Type

You can declare local, private module-level, or public module-level variables of the sameuser-defined type:

Dim MySystem As SystemInfo, YourSystem As SystemInfo

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 52: VB12

The following table illustrates where, and with what scope, you can declare user-definedtypes and their variables.

Procedure/ModuleYou can create a user -definedtype as...

Variables of a user -definedtype can be declared...

Procedures Not applicable Local only

Standard modules Private or public Private or public

Form modules Private only Private only

Class modules Private or public Private or public

Note If declared using the Dim keyword, user-defined types in Standard or Classmodules will default to Public. If you intend a user-defined type to be private, make sureyou declare it using the Private keyword.

Assigning and Retrieving Values

Assigning and retrieving values from the elements of this variable is similar to setting andgetting properties:

MySystem.CPU = "486"If MySystem.PurchaseDate > #1/1/92# Then

You can also assign one variable to another if they are both of the same user-defined type.This assigns all the elements of one variable to the same elements in the other variable.

YourSystem = MySystemUser-Defined Types that Contain Arrays

A user-defined type can contain an ordinary (fixed-size) array. For example:

Type SystemInfo CPU As Variant Memory As Long DiskDrives(25) As String ' Fixed-size array. VideoColors As Integer Cost As Currency PurchaseDate As VariantEnd Type

It can also contain a dynamic array.

Type SystemInfo CPU As Variant Memory As Long DiskDrives() As String ' Dynamic array. VideoColors As Integer Cost As Currency PurchaseDate As VariantEnd Type

You can access the values in an array within a user-defined type in the same way that youaccess the property of an object.

Dim MySystem As SystemInfoReDim MySystem.DiskDrives(3)MySystem.DiskDrives(0) = "1.44 MB"

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 53: VB12

You can also declare an array of user-defined types:

Dim AllSystems(100) As SystemInfo

Follow the same rules to access the components of this data structure.

AllSystems(5).CPU = "386SX"AllSystems(5).DiskDrives(2) = "100M SCSI"Passing User-Defined Types to Procedures

You can pass procedure arguments using a user-defined type.

Sub FillSystem (SomeSystem As SystemInfo) SomeSystem.CPU = lstCPU.Text SomeSystem.Memory = txtMemory.Text SomeSystem.Cost = txtCost.Text SomeSystem.PurchaseDate = NowEnd Sub

Note If you want to pass a user-defined type in a form module, the procedure must beprivate.

You can return user-defined types from functions, and you can pass a user-defined typevariable to a procedure as one of the arguments. User-defined types are always passed byreference, so the procedure can modify the argument and return it to the callingprocedure, as illustrated in the previous example.

Note Because user-defined types are always passed by reference, all of the datacontained in the user-defined type will be passed to and returned from the procedure. Foruser-defined types that contain large arrays, this could result in poor performance,especially in client/server applications where a procedure may be running on a remotemachine. In such a situation, it is better to extract and pass only the necessary data fromthe user-defined type.

For More Information To read more about passing by reference, see "PassingArguments to Procedures" in "Programming Fundamentals."

User-Defined Types that Contain Objects

User-defined types can also contain objects.

Private Type AccountPack frmInput as Form dbPayRollAccount as DatabaseEnd Type

Because the Variant data type can store many different types of data, a Variant array canbe used in many situations where you might expect to use a user-defined type. A Variantarray is actually more flexible than a user-defined type, because you can change the type ofdata you store in each element at any time, and you can make the array dynamic so thatyou can change its size as necessary. However, a Variant array always uses more memorythan an equivalent user-defined type.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 54: VB12

Nesting Data Structures

Nesting data structures can get as complex as you like. In fact, user-defined types cancontain other user-defined types, as shown in the following example. To make your codemore readable and easier to debug, try to keep all the code that defines user-defined datatypes in one module.

Type DriveInfo Type As String Size As LongEnd Type

Type SystemInfo CPU As Variant Memory As Long DiskDrives(26) As DriveInfo Cost As Currency PurchaseDate As VariantEnd Type

Dim AllSystems(100) As SystemInfoAllSystems(1).DiskDrives(0).Type = "Floppy"

The Setup Toolkit

The Setup Toolkit is a project installed with Visual Basic that is used by the Package andDeployment Wizard when it creates a setup program. The Setup Toolkit project containsthe forms and code that the application's setup program uses to install files onto the user'scomputer. When you use the Package and Deployment Wizard, the wizard includes thesetup1.exe file that the Setup Toolkit project creates. This file is used as the application'smain installation file.

Note There are two setup programs involved in the installation process — setup.exe andsetup1.exe. The setup.exe program performs pre-installation processing on the user'scomputer, including installing the setup1.exe program and any other files needed for themain installation program to run. Only setup1.exe is customizable through the SetupToolkit.

In addition to playing a supporting role in the process of creating a setup program, theSetup Toolkit can be used to modify the screens seen in the installation process, or tocreate a setup program directly. You might create a custom setup program if you need toadd additional functionality not supported by the wizard to your installation sequence.

The Setup Toolkit project resides in the \Wizards\PDWizard\Setup1 subdirectory of themain Visual Basic directory.

Caution The files in this project are the same files used by the output of the Package andDeployment Wizard. Do not modify them without making a backup copy in another

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 55: VB12

directory first. If you modify setup1.exe, subsequent setup programs created by thePackage and Deployment Wizard will use the modified version.

You use the Setup Toolkit by loading the Setup1.vbp file into Visual Basic and makingmodifications to the appearance or functionality of the project. In doing so, you may needto manually go through the steps that the Package and Deployment Wizard wouldotherwise do for you. The following sections describe steps in the process and explainhow to determine which files you need to include in your setup, how to create a Setup.lst,how to create distribution media, and how to test your setup.

Overall Steps to Modify the Package and Deployment Wizard

When you modify the Setup Toolkit with the intention of changing the output created bythe Package and Deployment Wizard, you follow these steps:

1. Modify the Setup Toolkit project to contain any new prompts, screens, functions, code, or otherinformation you want to include. When you are finished, compile the project to create setup1.exe.

2. Run the Package and Deployment Wizard, following the prompts on each screen, to create yourdistribution media.

Overall Steps to Create a Custom Setup Program

When you create a setup program manually using the Setup Toolkit rather than thePackage and Deployment Wizard, you must follow these steps:

1. If necessary, modify the Setup Toolkit project to contain any new prompts, screens, functions,code, or other information you want to include.

2. Determine the files you want to distribute, including all run-time, setup, and dependency files.

3. Determine where to install the files on the users' computers.

4. Manually create your Setup.lst file to reflect the names and installation locations of all files thatmust be included for your project.

5. Determine how you will be distributing files.

6. Create the .cab files for your project using the Makecab utility.

You can use the Package and Deployment Wizard to create your .cab files, then modifythe .cab files manually. When the wizard creates your .cab files, it creates a .ddf file and abatch file in the \Support subdirectory of your project directory. To modify the .cab files,edit the .ddf file, then run the batch file provided. The batch file in turn will runMakecab.exe to recreate your .cab files.

7. Create the setup1.exe for your project by compiling the Setup Toolkit project with your changes.

8. Copy your files to the distribution media, or manually publish your files to the Web site using theWeb Publishing Wizard, available in the ActiveX SDK.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 56: VB12

For More Information For more information on using the Web Publishing Wizard, see"Internet Tools and Technologies" in the Internet/Intranet/Extranet Services SDK. See"Modifying the Setup Project" later in this chapter for more information on modifying theSetup Toolkit project. See "Files you Need to Distribute" and "Where to Install Files onthe User's Machine" for more information on how to place files on the user's computer.See "Creating Distribution Media" for more information on copying your files to theappropriate media.

Visual Basic Concepts

Processing Multiple RDO Result Sets

Any SQL statement can include multiple SELECT statements or stored procedures thatinvoke one or more SELECT statements. Each SELECT statement generates a result setthat must be processed by your code or discarded before the RDO resources are releasedand the next result set is made available.

Action queries also generate row-less result sets that must also be processed — this isanother type of multiple result set query. In many cases, when you execute a storedprocedure, it might return more than one result set. It is often difficult to determine if astored procedure will return more than one result set because a stored procedure mightcall another procedure.

For example, if you submit a query that includes four SELECT queries to populate fourlocal ListBox controls and a stored procedure that updates a table, your code must dealwith at least five result sets. Because you might not know how many result sets can begenerated by a stored procedure, your code must be prepared to process n sets of results.

There are two approaches to executing queries with multiple result sets:

• Execute the OpenResultset method directly against a connection.

• Use the OpenResultset method against an rdoQuery.

Both are processed in similar ways, but if you use the rdoQuery, you can examine theRowsAffected property to determine the number of rows affected by action queries. Whileit is possible to execute a multiple result set query using the Execute method, it is notpossible to retrieve the rows affected from individual statements, and a trappable errorresults if any of the queries returns rows.

Using Server-Side Cursor Libraries with Multiple Result Sets

Not all cursor drivers support the ability to process queries that contain more than one setof results — the SQL Server server-side cursor driver is an example. However, if yourequest a cursorless result set by using the rdOpenForwardOnly, rdConcurReadOnlyoptions and by setting the RowsetSize property to 1, you can execute queries withmultiple result sets using server-side cursors. You can also set these options for all resultsets by setting the CursorDriver property to rdUseNone.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 57: VB12

Multiple Result Sets: An Example

This section takes you through a step-by-step procedure that demonstrates how to executea query with multiple result sets by using the rdoQuery object.

Whenever you use the concatenation operator "&" to build SQL queries, be sure toinclude white space (such as spaces or tabs) between the operators on separate lines.

1. Create your SQL statement and place it in a string variable — for instance, MySQL. For SQLServer, multiple statements must be separated by semi-colons.

2. Dim MySQL As String3. MySQL = "Select Name from Authors Where ID = 5; " _4. & " Select City from Publishers; " _5. & " Update MyTable " _6. & " Set Age = 18 Where Name = 'Fred'"

7. Next, create a new rdoQuery and set a variable declared as rdoQuery and multiple result sets tothis object — in this case, MyQy. The example assumes an rdoConnection object (Cn) alreadyexists. There are a number of other ways to instantiate and initialize rdoQuery objects; thisexample illustrates only one of these ways.

8. Dim MyQy As rdoQuery9. Set MyQy = Cn.CreateQuery("MyQy1", "")10. MyQy.SQL = MySQL

11. Execute the query by using the OpenResultset method against the rdoQuery object. If you do notneed the extra properties and the ability to pass parameters to the query, you can use theOpenResultset method directly against the rdoConnection object. The arguments you use hereaffect all result sets fetched from this query. For example, if you need to use a cursor on thesecond result set, you must specify a cursor type when the first result set is opened.

12. Dim MyRs As rdoResultset13. Set MyRs = MyQy.OpenResultset(rdOpenForwardOnly, _14. rdConcurReadOnly)

15. You are now ready to process the first result set. Note that the rdAsyncEnable options argumentwas not set. Because of this, control is not returned to the application until the first row of thefirst result set is ready for processing. If the current rdoResultset contains rows, the RowCountproperty is set to a value > 0, and the EOF and BOF properties are both False. If no rows werereturned, the RowCount property returns either –1 to indicate that the number of rows is notavailable, or 0, depending on the driver and data source.

The following example fills a ListBox control called NameList1 with the results ofthe query.

While Not MyRs.EOF ' Loop through all rows. ' Use the first column. NameList1.AddItem = MyRs(0) MyRs.MoveNext ' Position to the next row ' in the result set.Wend

16. The first result set is now at end-of-file (MyRs.EOF = True). Use the MoreResults method toactivate the next result set. Once you execute MoreResults, the first set of rows is no longeravailable — even if you used one of the cursor options to create it.

17. ' Activate the next set of results.18. If (MyRs.MoreResults) Then ...

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 58: VB12

19. You are now ready to process the second result set. This example uses only the first few namesand discards the remaining rows.

20. ' Loop through some rows.21. Do While Not MyRs.EOF and MyRs(0) < "B"22. ' Use the first column.23. NameList1.AddItem = MyRs(0)24. MyRs.MoveNext25. Loop26. ' Activate the next set of results27. ' and discard remaining rows.28. If (MyRs.MoreResults) Then ...

29. You are now ready to process the last set of results. Because this is an UPDATE statement, thereare no rows to be returned, but you can determine the number of rows affected by using theRowsAffected property. The MoreResults method is used for the last time to release all resourcesconnected with this query.

30. If MyQy.RowsAffected = 0 Then31. MsgBox "No rows were updated"32. End If33. ' Activate the next set of results.34. If (MyRs.MoreResults) Then ...

When you use the MoreResults method against the last result set, it should return Falseand other resources required to process the query are released. At this point the rdoQueryobject can be reused. If you use the Close method against an rdoQuery object, it isremoved from the rdoQueries collection.

Visual Basic Concepts

Tabstrip Scenario: Create a Tabbed Dialog Box

The TabStrip control is used to create dialog boxes which contain a number of tabs. Eachtab usually has some relationship to a larger theme, and is therefore related to other tabs inthe same dialog box. In this scenario, we create a tabbed dialog box which sets the fonts,and indents of a RichTextBox.

The following objects are used in the code below:

• Form object named "frmRTF"

• RichTextBox control named "rtfData"

• TabStrip control named "tabRTF"

• Form object named "frmTab"

• Frame control named "fraTab"

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 59: VB12

• ComboBox named "cmbFonts"

• OptionButton control named "optNormal"

• OptionButton control named "optBullet"

To create a Tabbed Dialog Box

1. Create two forms, one named "frmRTF" to contain the RichTextbox, and a second named"frmTab" to contain the TabStrip control.

2. At design time, create two Tab objects on the TabStrip control.

3. Create a Frame control array named "fraTab" on frmTab.

4. Draw the ComboBox on fraTab(0) and two OptionButton controls on fraTab(1).

5. Use the Move method in the Load event to position the Frame controls.

6. In the TabStrip control's Click event, use the SelectedItem property to determine the Index of theclicked Tab.

7. Use the Index with the ZOrder method to bring the right Frame to the front.

Create two Forms, One Named "frmRTF" to Contain the RichTextbox, and a SecondNamed "frmTab" to Contain the TabStrip Control

This scenario requires two forms: the first is named "frmRTF," and contains theRichTextBox control, the second, named "frmTab", contains the TabStrip control.

To create two Form objects

1. On the File menu, click New Project to display the New Project dialog box.

2. Double-click the Standard EXE Project icon, and a new form named Form1 will be created foryou.

3. If the Proper ties window is not showing, press F4 to display it.

4. Click the Name box and type "frmRTF."

5. Draw a RichTextBox control on the form.

Note You must have the RichTextBox (RichTx32.ocx) loaded into the Toolbox.See "Loading ActiveX Controls" for more information.

6. On the Proper ties page window, click the Name box and type "rtfData"

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 60: VB12

7. On the Project Explorer window, click Add Form to display the Add Form dialog box.

8. Double-click the Form icon to insert another form into the project.

9. On the Proper ties window, click the name box and type "frmTab."

10. Draw a TabStrip control on frmTab, and name it "tabRTF."

You must also have some code that shows the second form. A quick way to do this wouldbe to place a Show method in the DblClick event of the first Form object (frmRTF), asshown below:

Private Sub Form_DblClick() frmTab.ShowEnd SubAt Design time, Create Two Tab Objects on the TabStrip Control

You can create Tab objects at design time and at run time. In this scenario, you shouldcreate the two tabs at design time. Right-click on the TabStrip control and click Propertiesto display the Property Pages dialog box. Then click the Tabs tab and click Insert Tabtwice. Be sure to give the tabs appropriate captions — "Fonts," and "Indents."

Create a Control Array Named "fraTab" on frmTab

A TabStrip control functions by managing Tab objects. Each Tab object is associated witha container control that appears in the tab's client area. It's most efficient to use a controlarray to create the container controls. In this scenario, draw a Frame control on the sameform as the TabStrip control, and name it "fraTab."

To create a control array

1. Draw a Frame control on frmTab.

2. Click the Name box on the Proper ties window and type "fraTab."

3. Click the Frame control and copy it to the clipboard by either pressing CTRL+C or clickingCopy from the Edit menu.

4. Paste the same control back on the form by pressing CTRL+V. A dialog box will ask you if youwant to create a control array. Click Yes.

Draw the ComboBox on fraTab(0) and Two OptionButton controls on fraTab(1)

On the control named fraTab(0), draw a ComboBox control, and name it "cmbFonts." Topopulate the ComboBox with all available fonts on your system, use the following code:

Private Sub Form_Load() Dim i ' Declare variable. ' Determine number of fonts. For i = 0 To Printer.FontCount - 1 ' Put each font into list box. cmbFonts.AddItem Printer.Fonts(I)

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 61: VB12

Next i cmbFonts.ListIndex = 0End Sub

To set the SelFontName property of the RichTextBox control, use the following code:

Private Sub cmbFonts_Click() frmRtf.rtfData.SelFontName = cmbFonts.TextEnd Sub

Draw two OptionButton controls on the second Frame control named fraTab(0). Namethe first OptionButton control "optNormal," and change its Caption property to "Normal."Name the second control "optBullet," and set its Caption property to "Bullet." The codefor these controls sets the SelBullet property to True or False. The code for each is shownbelow:

Private Sub optBullet_Click() ' The Form object's ScaleMode is set to Twips. frmRTF.rtfData.BulletIndent = 500 frmRTF.rtfData.SelBullet = TrueEnd Sub

Private Sub optNormal_Click() frmRTF.rtfData.SelBullet = FalseEnd SubUse the Move Method in the Load Event to Position the Frame Controls

To position the Frame controls over the client area, use the Move method in the Formobject's Load event, as shown below:

Private Sub Form_Load() ' The name of the TabStrip is "tabRTF." ' The Frame control is named "fraTab." For i = 0 To fraTab.Count - 1 With fraTab(i) .Move tabRTF.ClientLeft, _ tabRTF.ClientTop, _ tabRTF.ClientWidth, _ tabRTF.ClientHeight End With Next I

' Bring the first fraTab control to the front. fraTab(0).ZOrder 0End SubIn the TabStrip Control's Click Event, Use the SelectedItem Property to Determine theIndex of the Clicked Tab

To determine which Tab object, use the SelectedItem property. This property returns areference to the clicked tab. However, the Tabs collection is a 1-based collection (thecollection index begins with 1), and the fraTab array is a 0-based collection. To make surethe two are synchronized, subtract 1 from the Index, as shown below.

Private Sub tabRTF_Click()fraTab(tabRTF.SelectedItem.Index - 1).ZOrder 0

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 62: VB12

End Sub

Tip At design time, you can set the Index property of the Frame control array to becomea 1-based array. Thus the code above would read:

fraTab(tabRTF.SelectedItem.Index).ZOrder 0The Complete Code

The complete code is shown below:

Private Sub Form_Load() Dim i As Integer' Declare variable. ' Determine number of fonts. For i = 0 To Printer.FontCount - 1 ' Put each font into list box. cmbFonts.AddItem Printer.Fonts(i) Next i

cmbFonts.ListIndex = 0

' The name of the TabStrip is "tabRTF." ' The Frame control is named "fraTab." For i = 0 To fraTab.Count - 1 With fraTab(i) .Move tabRTF.ClientLeft, _ tabRTF.ClientTop, _ tabRTF.ClientWidth, _ tabRTF.ClientHeight End With Next i

' Bring the first fraTab control to the front. fraTab(0).ZOrder 0End Sub

Private Sub cmbFonts_Click() frmRTF.rtfData.SelFontName = cmbFonts.TextEnd Sub

Private Sub optBullet_Click() frmRTF.rtfData.BulletIndent = 500 frmRTF.rtfData.SelBullet = TrueEnd Sub

Private Sub optNormal_Click() frmRTF.rtfData.SelBullet = False

End Sub

Private Sub tabRTF_Click() fraTab(tabRTF.SelectedItem.Index - 1).ZOrder 0End Sub

This following code goes into the form named "frmRTF."

Private Sub Form_DblClick()

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 63: VB12

frmTab.ShowEnd Sub

Visual Basic Concepts

Life Cycle of Visual Basic Forms

Because they're visible to the user, forms and controls have a different life cycle than otherobjects. For example, a form will not close just because you've released all your referencesto it. Visual Basic maintains a global collection of all forms in your project, and onlyremoves a form from that collection when you unload the form.

In similar fashion, Visual Basic maintains a collection of controls on each form. You canload and unload controls from control arrays, but simply releasing all references to acontrol is not sufficient to destroy it.

For More Information The Forms and Controls collections are discussed in"Collections in Visual Basic" earlier in this chapter.

States a Visual Basic Form Passes Through

A Visual Basic form normally passes through four states in its lifetime:

1. Created, but not loaded.

2. Loaded, but not shown.

3. Shown.

4. Memory and resources completely reclaimed.

There's a fifth state a form can get into under certain circumstances: Unloaded andunreferenced while a control is still referenced.

This topic describes these states, and the transitions between them.

Created, But Not Loaded

The beginning of this state is marked by the Initialize event. Code you place in theForm_Initialize event procedure is therefore the first code that gets executed when a formis created.

In this state, the form exists as an object, but it has no window. None of its controls existyet. A form always passes through this state, although its stay there may be brief.

For example, if you execute Form1.Show, the form will be created, and Form_Initialize willexecute; as soon as Form_Initialize is complete, the form will be loaded, which is the nextstate.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 64: VB12

The same thing happens if you specify a form as your Startup Object, on the General tabof the Project Properties dialog box (which is available from the Project menu). A formspecified as the Startup Object is created as soon as the project starts, and is thenimmediately loaded and shown.

Note You can cause your form to load from within Form_Initialize, by calling its Showmethod or by invoking its built-in properties and methods, as described below.

Remaining Created, But Not LoadedBy contrast, the following code creates an instance of Form1 without advancing the formto the loaded state:

Dim frm As Form1Set frm = New Form1

Once Form_Initialize has ended, the only procedures you can execute without forcing theform to load are Sub, Function, and Property procedures you've added to the form's codewindow. For example, you might add the following method to Form1:

Public Sub ANewMethod() Debug.Print "Executing ANewMethod"End Sub

You could call this method using the variable frm (that is, frm.ANewMethod) without forcingthe form on to the next state. In similar fashion, you could call ANewMethod in order tocreate the form:

Dim frm As New Form1frm.ANewMethod

Because frm is declared As New, the form is not created until the first time the variable isused in code — in this case, when ANewMethod is invoked. After the code above isexecuted, the form remains created, but not loaded.

Note Executing Form1.ANewMethod, without declaring a form variable, has the same effectas the example above. As explained in "Customizing Form Classes," Visual Basic creates ahidden global variable for each form class. This variable has the same name as the class;it's as though Visual Basic had declared Public Form1 As New Form1.

You can execute as many custom properties and methods as you like without forcing theform to load. However, the moment you access one of the form's built-in properties, orany control on the form, the form enters the next state.

Note You may find it helpful to think of a form as having two parts, a code part and avisual part. Before the form is loaded, only the code part is in memory. You can call asmany procedures as you like in the code part without loading the visual part of the form.

The Only State All Forms Pass ThroughCreated, But Not Loaded is the only state all forms pass through. If the variable frm in theexamples above is set to Nothing, as shown here, the form will be destroyed beforeentering the next state:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 65: VB12

Dim frm As New Form1frm.ANewMethodSet frm = Nothing ' Form is destroyed.

A form used in this fashion is no better than a class module, so the vast majority of formspass on to the next state.

Loaded, But Not Shown

The event that marks the beginning of this state is the familiar Load event. Code you placein the Form_Load event procedure is executed as soon as the form enters the loaded state.

When the Form_Load event procedure begins, the controls on the form have all beencreated and loaded, and the form has a window — complete with window handle (hWnd)and device context (hDC) — although that window has not yet been shown.

Any form that becomes visible must first be loaded.

Many forms pass automatically from the Created, But Not Loaded state into the Loaded,but Not Shown state. A form will be loaded automatically if:

• The form has been specified as the Startup Object, on the General tab of the Project Propertiesdialog box.

• The Show method is the first property or method of the form to be invoked, as for exampleForm1.Show.

• The first property or method of the form to be invoked is one of the form's built-in members, asfor example the Move method.

Note This case includes any controls on the form, because each control defines aproperty of the form; that is, in order to access the Caption property ofCommand1, you must go through the form's Command1 property:Command1.Caption.

• The Load statement is used to load the form, without first using New or As New to create theform, as described earlier.

Forms That Are Never ShownIn the first two cases listed above, the form will continue directly on to the visible state, assoon as Form_Load completes. In the last two cases, the form will remain loaded, but notshown.

It has long been common coding practice in Visual Basic to load a form but never show it.This might be done for several reasons:

• To use the Timer control to generate timed events.

• To use controls for their functionality, rather than their user interface — for example, for serialcommunications or access to the file system.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 66: VB12

• To execute DDE transactions.

Note With the Professional or Enterprise edition, you can create ActiveX components(formerly called OLE servers), which are often better at providing code-only functionalitythan controls are. See Creating ActiveX Components in the Component Tools Guide.

Always Coming HomeForms return from the visible state to the loaded state whenever they're hidden. Returningto the loaded state does not re-execute the Load event, however. Form_Load is executedonly once in a form's life.

Shown

Once a form becomes visible, the user can interact with it. Thereafter, the form may behidden and shown as many times as you like before finally being unloaded.

Interlude: Preparing to Unload

A form may be either hidden or visible when it's unloaded. If not explicitly hidden, itremains visible until unloaded.

The last event the form gets before unloading is the Unload event. Before this eventoccurs, however, you get a very important event called QueryUnload. QueryUnload isyour chance to stop the form from unloading. If there's data the user might like to save,this is the time to prompt the user to save or discard changes.

Important Setting the Cancel argument of the QueryUnload to True will stop the formfrom unloading, negating an Unload statement.

One of most powerful features of this event is that it tells you how the impending unloadwas caused: By the user clicking the Close button; by your program executing the Unloadstatement; by the application closing; or by Windows closing. Thus QueryUnload allowsyou to offer the user a chance to cancel closing the form, while still letting you close theform from code when you need to.

Important Under certain circumstances, a form will not receive a QueryUnload event: Ifyou use the End statement to terminate your program, or if you click the End button (orselect End from the Run menu) in the development environment.

For More Information See "QueryUnload Event" in the Language Reference.

Returning to the Created, But Not Loaded State

When the form is unloaded, Visual Basic removes it from the Forms collection. Unlessyou've kept a variable around with a reference to the form in it, the form will be destroyed,and its memory and resources will be reclaimed by Visual Basic.

If you kept a reference to the form in a variable somewhere, such as the hidden globalvariable described in "Customizing Form Classes," then the form returns to the Created,But Not Loaded state. The form no longer has a window, and its controls no longer exist.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 67: VB12

The object is still holding on to resources and memory. All of the data in the module-levelvariables in the form's code part are still there. (Static variables in event procedures,however, are gone.)

You can use that reference you've been keeping to call the methods and properties thatyou added to the form, but if you invoke the form's built-in members, or access itscontrols, the form will load again, and Form_Load will execute.

Memory and Resources Completely Reclaimed

The only way to release all memory and resources is to unload the form and then set allreferences to Nothing. The reference most commonly overlooked when doing this is thehidden global variable mentioned earlier. If at any time you have referred to the form by itsclass name (as shown in the Properties Window by the Name property), you've used thehidden global variable. To free the form's memory, you must set this variable to Nothing.For example:

Set Form1 = Nothing

Your form will receive its Terminate event just before it is destroyed.

Tip Many professional programmers avoid the use of the hidden global variable,preferring to declare their own form variables (for example, Dim dlgAbout As New

frmAboutBox) to manage form lifetime.

Note Executing the End statement unloads all forms and sets all object variables in yourprogram to Nothing. However, this is a very abrupt way to terminate your program. Noneof your forms will get their QueryUnload, Unload, or Terminate events, and objectsyou've created will not get their Terminate events.

Unloaded and Unreferenced, But a Control Is Still Referenced

To get into this odd state, you have to unload and free the form while keeping a referenceto one of its controls. If this sounds like a silly thing to do, rest assured that it is.

Dim frm As New Form1Dim obj As Objectfrm.Show vbModal' When the modal form is dismissed, save a' reference to one of its controls.Set obj = frm.Command1Unload frmSet frm = Nothing

The form has been unloaded, and all references to it released. However, you still have areference to one of its controls, and this will keep the code part of the form from releasingthe memory it's using. If you invoke any of the properties or methods of this control, theform will be reloaded:

obj.Caption = "Back to life"

The values in module-level variables will still be preserved, but the property values of allthe controls will be set back to their defaults, as if the form were being loaded for the firsttime. Form_Load will execute.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 68: VB12

Note In some previous versions of Visual Basic, the form did not completely re-initialize,and Form_Load did not execute again.

Note Not all forms behave as Visual Basic forms do. For example, the Microsoft Formsprovided in Microsoft Office don't have Load and Unload events; when these formsreceive their Initialize events, all their controls exist and are ready to use.

For More Information Forms are discussed in "Designing a Form" in "Forms, Controls,and Menus" and in "More About Forms" in "Creating a User Interface."

Visual Basic Concepts

Data Limitations

The following limitations apply to variables in the Visual Basic language.

Form, Standard, and Class Module Data

The data segment (that is, the data defined in the Declarations section) of the VBAmodule of any form or module in Visual Basic can be up to 64K. This data segmentcontains the following data:

• Local variables declared with Static.

• Module-level variables other than arrays and variable-length strings.

• 4 bytes for each module-level array and variable-length string.

Procedures, Types, and Variables

If a procedure or module exceeds the 64K code limit, Visual Basic generates a compile-time error.

If you define a procedure that has more than 64K of local variables defined, you get theerror "Too many local nonstatic variables."

If you define a module that has more than 64K of module-level variables defined, or if youdefine a User-Defined Type larger than 64K, you get the error "Fixed or static data can'tbe larger than 64K."

If you encounter this error, you can avoid it by breaking extremely large procedures intoseveral smaller procedures, or by moving module-level declarations into another module.

An array declared as a variable doesn't contribute to the entire size of the array; only thearray descriptor counts toward the 64K limit. So it is acceptable, for example, to have adeclaration such as Dim x(1000000) As Byte either in a procedure or at module level. Out ofmemory problems occur, however, if you declare a large, fixed-size array in a record, thendeclare instances of those records as variables.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 69: VB12

User-Defined Types

No variable of a user-defined type can exceed 64K, although the sum of variable-lengthstrings in a user-defined type may exceed 64K (variable-length strings occupy only 4 byteseach in the user-defined type; the actual contents of a string are stored separately). User-defined types can be defined in terms of other user-defined types, but the total size of thetypes cannot exceed 64K.

Stack Space

Arguments and local variables in procedures take up stack space at run time. Module-leveland static variables do not take up stack space because they are allocated in the datasegment for forms or modules. Any DLL procedures you call use this stack while they areexecuting.

Visual Basic itself uses some of the stack for its own purposes, such as storingintermediate values when evaluating expressions.

Total available stack size for Visual Basic is one megabyte (1MB) per thread. A stack maygrow beyond this, however, if there is adjacent free memory.

Visual Basic Concepts

Tips for Debugging

There are several ways to simplify debugging:

• When your application doesn't produce correct results, browse through the code and try to findstatements that may have caused the problem. Set breakpoints at these statements and restart theapplication.

• When the program halts, test the values of important variables and properties. Use Quick Watchor set watch expressions to monitor these values. Use the Immediate window to examinevariables and expressions.

• Use the Break on All Errors option to determine where an error occurred. To temporarily changethis option, select Toggle from the Code window context menu, then toggle the option from thesubmenu. Step through your code, using watch expressions and the Locals window to monitorhow values change as the code runs.

• If an error occurs in a loop, define a break expression to determine where the problem occurs.Use the Immediate window together with Set Next Statement to re-execute the loop after makingcorrections.

• If you determine that a variable or property is causing problems in your application, use aDebug.Assert statement to halt execution when the wrong value is assigned to the variable orproperty.

• To set the error trapping state that Visual Basic defaults to at the beginning of any debuggingsession, open the Options dialog box (available from the Tools menu), select the General tab, and

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 70: VB12

set the Default Error Trapping State option. Visual Basic will use this setting the next time youstart it, even if the setting was entered for another project.

Occasionally you may encounter a bug that’s especially difficult to track down. Don’tpanic – here are some things that you can do:

• First and foremost, make a backup. This is the point at which even experienced programmersfrequently lose many hours of work. When you experiment, it is far too easy to accidentallyoverwrite or delete necessary sections of code.

• Use the debugging facilities built in to Visual Basic. Attempt to identify the line or lines of codegenerating the error. Isolate the code. If you can isolate the problem to one block of code, try toreproduce the same problem with this block of code separated from the rest of your program.Select the code, copy it, start a new project, paste the code into the new project, run the newproject, and see if the error still occurs.

• Create a log file. If you cannot isolate the code or if the problem is erratic or if the problem onlyhappens when compiled, then the debugging facility of Visual Basic will be less effective. Inthese situations you can create a log file which records the activity of your program. This willallow you to progressively isolate the location of the suspect code. Call the following procedurefrom various points in your program. You should pass in a string of text which indicates thecurrent location of the code executing in your program.

• Sub LogFile (Message As String)• Dim LogFile As Integer• LogFile = FreeFile• Open "C:\VB\LogFile.Log" For Append As #LogFile• Print #LogFile, Message• Close #LogFile• End Sub• • Sub Sub1 ()• '...• Call LogFile("Here I am in Sub1")• '...• End Sub

• Simplify the problem. If possible, remove any third party controls and custom controls from yourproject. Replace them with Visual Basic standard controls. Eliminate any code that does not seemto relate to the problem.

• Reduce the search space. If you cannot resolve the problem with any of the above methods, thenit is time to eliminate all other non-Visual Basic causes from the problem search space. Copyyour AUTOEXEC.BAT and CONFIG.SYS files to backup files. Comment out any and all driversand programs from these two files that are not absolutely essential to running your programunder Windows. Change your Windows video driver to the standard Windows VGA driver. Shutdown Windows and reboot your machine. This will eliminate the possibility that there is someother program or driver which is interfering with your program.

• If you cannot locate a solution and are unable to isolate or resolve the problem with any of thesemethods, it's time to look for help. See the technical support documentation.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 71: VB12

For More Information Breakpoints are described in "Using a Breakpoint to SelectivelyHalt Execution" earlier in this chapter. Read more about Watch expressions in"Monitoring Data with Watch Expressions." The Immediate window is discussed in"Testing Data and Procedures with the Immediate Window." See "Verifying Your Codewith Assertions" for more about the Assert method of the Debug object.

Visual Basic Concepts

How to Handle Focus in Your Control

The way you handle focus for your control depends on which model you're using todevelop your control. Models for building ActiveX controls are discussed in "Three Waysto Build ActiveX Controls," earlier in this chapter.

Important If you're authoring a control that can be a container for other controls, asdescribed in "Allowing Developers to Put Controls on Your Control," note that thematerial in this topic does not apply to controls a developer places on an instance of yourcontrol. These contained controls will receive focus independent of your control and itsconstituent controls.

User-Drawn Controls

If you're authoring a user-drawn control, there won't be any constituent controls on yourUserControl. If you don't want your control to be able to receive the focus, set theCanGetFocus property of the UserControl object to False. CanGetFocus is True bydefault.

If your user-drawn control can receive the focus, the UserControl object will receiveGotFocus and LostFocus events when your control receives and loses the focus. A user-drawn control is responsible for drawing its own focus rectangle when it has the focus, asdescribed in "User-Drawn Controls," in this chapter.

This is the only function your UserControl's GotFocus and LostFocus events need to fulfillfor a user-drawn control. You don't need to raise GotFocus or LostFocus events for theuser of your control, because the container's extender provides these events if theCanGetFocus property is True.

Note The UserControl object of a user-drawn control will also receive a EnterFocusevent prior to GotFocus, and an ExitFocus event after LostFocus. You don't need to putany code in the event procedures of these event, and in fact it is recommended that younot do so.

User-drawn controls can respond to access keys, as described later in this topic.

Controls That Use Constituent Controls

If you're authoring a control that enhances a single constituent control, or is an assemblyof constituent controls, your UserControl object will be unable to receive the focus,

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 72: VB12

regardless of the setting of the CanGetFocus property, unless none of its constituentcontrols can receive the focus.

If no constituent controls can receive the focus, and CanGetFocus is True, then yourUserControl object will receive the same events a user-drawn control receives. The onlything you need to do with these events is provide a visual indication that your control hasthe focus.

How Constituent Controls Are Affected by CanGetFocusIf your control contains at least one constituent control that can receive the focus, theCanGetFocus property of the UserControl object must be set to True. If you attempt toset CanGetFocus to False on a UserControl that has constituent controls that can receivefocus, an error will occur.

Visual Basic will not allow a constituent control that can receive focus to be placed on aUserControl whose CanGetFocus property is False: Icons of controls that can receivefocus are disabled in the Toolbox when the UserControl's design window is active.

EnterFocus and ExitFocusWhen the focus moves from outside your control to any of your control's constituentcontrols, the UserControl object will receive an EnterFocus event. The GotFocus eventfor the constituent control that receives the focus will be raised after theUserControl_EnterFocus event procedure.

As long as the focus remains within your control, the UserControl object's focus-relatedevents will not be raised. As the focus moves from one constituent control to another,however, the appropriate GotFocus and LostFocus events of the constituent controls willbe raised.

When the focus moves back outside your control, the last constituent control that had thefocus will receive its LostFocus event. When the event procedure returns, the UserControlobject will receive its ExitFocus event.

You can use the EnterFocus event to change which constituent control receives the focus.You may wish to do this in order to restore the focus to the constituent control that lasthad it, rather than simply allowing the first constituent control in your UserControl's taborder to receive the focus, which is the default behavior.

Tip If your control is complex — as for example an Address control with multipleconstituent controls — you may be tempted to validate the data in the ExitFocus event.Don't. The user of your control can put code in the Validate event of the user control tohandle data validation as they see fit. If it's absolutely necessary to validate data inside thecontrol, use the Validate events in combination with the CausesValidation properties ofthe constituent controls. Be aware that you can't always count on the Validate event forconstituent controls, as is discussed in "Handling the Validate Event" below.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 73: VB12

Tip Generally speaking, it's not a good idea to use MsgBox when you're debuggingfocus-related events, because the message box immediately grabs the focus. It's a very badidea to use MsgBox in EnterFocus and ExitFocus events. Use Debug.Print instead.

Receiving Focus via Access Keys

Avoid hard coding access keys for your control's constituent controls, because access keyspermanently assigned to your control in this fashion will limit a user's freedom to chooseaccess keys for her form. In addition, two instances of your control on the same form willhave access key conflicts.

"Allowing Developers to Set Access Keys for Your Control," later in this chapter,discusses how you can give the user of your control the ability to set access keys oninstances of your control.

Forwarding Focus to the Next Control in the Tab OrderIf your control cannot receive the focus itself, and has no constituent controls that canreceive the focus, you can give your control the same behavior displayed by Labelcontrols. That is, when the access key for your control is pressed, the focus is forwardedto the next control in the tab order.

To enable this behavior, set the ForwardFocus property of the UserControl object toTrue.

Handling the Validate EventThe Validate event and CausesValidation property for a user control behave exactly likethey do for any other control, but the behavior of Validate and CausesValidation forconstituent controls may not yield the expected results. Let's review the standard behavior.When a control loses focus, its Validation event is fired before its LostFocus event — butonly if the control about to receive the focus has its CausesValidation property set toTrue. This allows you to handle data validation before the control loses focus.

A user control exposes a Validate event and, via the Extender object, exposes aCausesValidation property. Code in the Validate event is executed when the focus isshifted from the user control to any control that had its CausesValidation property set toTrue; setting the CausesValidation property of the user control to True will enable theValidation event for any control passing focus to the user control.

The Validate event and CausesValidation property for constituent controls work asexpected as long as the focus remains inside the user control. When the focus is shiftedoutside of the user control, the Validate event for the constituent control isn't fired. Forthat reason, it's best to avoid trying to handle validation within a user control.

Visual Basic Concepts

Using the MaskedEdit Control

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 74: VB12

The MaskedEdit control is used to prompt users for data input using a mask pattern. Youcan also use it to prompt for dates, currency, and time, or to convert input data to allupper- or lowercase letters. For example, to prompt the user to enter a phone number, youcan create the following input mask: "(___) - ___ - ____". If you don't use an input mask,the MaskedEdit control behaves much like a standard text box.

When you define an input mask using the Mask property, each character position in theMaskedEdit control maps to a placeholder of a specified type, or to a literal character.Literal characters, or literals, give visual cues about the type of data being used. Forexample, the parentheses surrounding the area code of a telephone number are literals:(206).

The input mask prevents users from entering invalid characters into the control. If the userattempts to enter a character that conflicts with the input mask, the control generates aValidationError event.

The MaskedEdit control is a bound control and can be used with a data control to displayor update field values in a data set.

Possible Uses

• To prompt for date/time, number, or currency information.

• To prompt for custom mask formats such as a telephone number or any other input that follows apattern.

• To format the display and printing of mask input data.

• To work with a data control to display and update field values in a data set.

The Mask Property

The Mask property determines the type of information that is input into the MaskedEditcontrol. The Mask property uses characters such as the pound sign (#), backslash (\),comma (,), and ampersand (&) as placeholders that define the type of input. The followingtable lists all the characters you can use to set the Mask property:

Maskcharacter

Descr iption

# Digit placeholder.

. Decimal placeholder. The actual character used is the one specified as the decimalplaceholder in your international settings. This character is treated as a literal formasking purposes.

, Thousands separator. The actual character used is the one specified as the thousandsseparator in your international settings. This character is treated as a literal formasking purposes.

: Time separator. The actual character used is the one specified as the time separatorin your international settings. This character is treated as a literal for maskingpurposes.

/ Date separator. The actual character used is the one specified as the date separator in

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 75: VB12

your international settings. This character is treated as a literal for maskingpurposes.

\ Treat the next character in the mask string as a literal. This allows you to include the'#', '&', 'A', and '?' characters in the mask. This character is treated as a literal formasking purposes.

& Character placeholder. Valid values for this placeholder are ANSI characters in thefollowing ranges: 32-126 and 128-255.

> Convert all the characters that follow to uppercase.

< Convert all the characters that follow to lowercase.

A Alphanumeric character placeholder (entry required). For example: a z, A Z, or 0 9.

a Alphanumeric character placeholder (entry optional).

9 Digit placeholder (entry optional). For example: 0 9.

C Character or space placeholder (entry optional).

? Letter placeholder. For example: a z or A Z.

Literal All other symbols are displayed as literals; that is, as themselves.

To create an input mask, you combine mask characters with literal characters. Literalcharacters are characters which rather than representing some data type or format, areused as themselves. For example, to create an input mask for a phone number you definethe Mask property as follows:

MaskEdBox1.Mask = (###) - ### - ####

The pound sign (a digit placeholder) is used with the left and right parentheses and thehyphen (literal characters). At run time, the MaskedEdit control would look like thefollowing:

A MaskedEdit control with a phone number mask

When you define an input mask, the insertion point automatically skips over literals as youenter data or move the insertion point.

The Text and ClipText Properties

All data entered in the MaskedEdit control is contained in and can be retrieved from theText property. This is a run time only property and includes all the literal and promptcharacters of the input mask. For instance, retrieving data from the Text property of theexample above returns the string "(555) - 555 - 5555" – the phone number that wasentered.

The ClipText property also returns data entered in the MaskedEdit control, but withoutthe literal and prompt characters. Using the example above, retrieving data from theClipText property returns the string "5555555555". The ClipText property is availableonly at run time.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 76: VB12

Defining the Input Character

By default, all mask characters are underlined. This indicates to the user that the characteris a placeholder for data input. When the user enters a valid character, the underlinedisappears. If you want the underline to remain, you can set the FontUnderline property ofthe MaskedEdit control to True.

You can also change the underline input character to a different character by using thePromptChar property. For example, to change the underline (_) character to the asterisk(* ) character, you simply redefine the value of the PromptChar property:

MaskEdBox1.PromptChar = "* "Using Mask Characters as Literals

If you want to use a mask character as a literal, you can precede the mask character with abackslash (\). For example, if you want the pound sign (#) to display, you set the mask asfollows:

MaskEdBox1.Mask = "\##"

This would produce a mask that displays a pound sign (#) followed by a blank space forentering a number.

The Format Property

You can modify how the MaskedEdit control is displayed and printed using the Formatproperty. The Format property provides you with standard formats for displaying number,currency, and date/time information.

The following table lists the standard formats you can use with the Format property:

Data type Value Descr iption

Number (Default) Empty string General Numeric format. Displays as entered.

Number $#,##0.00;($#,##0.00) Currency format. Uses thousands separator; displaysnegative numbers enclosed in parentheses.

Number 0 Fixed number format. Displays at least one digit.

Number #,##0 Commas format. Uses commas as thousandsseparator.

Number 0% Percent format. Multiplies value by 100 and appendsa percent sign.

Number 0.00E+00 Scientific format. Uses standard scientific notation.

Date/Time (Default) c General Date and Time format. Displays date ,time, or both.

Date/Time Dddddd Long Date format. Same as the Long Date setting inthe International section of the Microsoft WindowsControl Panel. Example: Tuesday, May 26, 1992.

Date/Time dd-mmm-yy Medium Date format. Example: 26-May-92.

Date/Time Ddddd Short Date format. Same as the Short Date setting inthe International section of the Microsoft WindowsControl Panel. Example: 5/26/92.

Date/Time Ttttt Long Time format. Same as the Time setting in theInternational section of the Microsoft Windows

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 77: VB12

Control Panel. Example: 05:36:17 A.M.

Date/Time hh:mm A.M./P.M. Medium Time format. Example: 05:36 A.M.

Date/Time hh:mm Short Time format. Example: 05:36.

You use the Format property with the Mask property. For example, to create a mask thatprompts for a Short Date input that displays in the Long Date format, you set the Maskand Format properties as follows:

MaskEdBox1.Mask = "##-##-##"MaskEdBox1.Format = "dddddd"

When the user enters the date in the short format (06-27-96, for instance), the MaskedEditcontrol verifies that the entered data is valid, and then, when the focus passes to the nextcontrol, it is displayed as "Thursday, June 27, 1996".

Note To automatically shift the focus to the next control when the data has been verifiedas valid, set the AutoTab property of the MaskedEdit control to True.

The Format property also allows you to specify custom formatting using the same formatexpressions defined by the Visual Basic Format function.

For More Information See "Format Function" or "Format Property (MaskedEditcontrol)."

Setting Properties at Design Time

You can set the property values at design time using the MaskedEdit control PropertyPages. Click the Custom option in the Properties window of the MaskedEdit control tobring up the Property Pages dialog box, as shown below:

You enter the mask and format patterns as in the run time examples above. The Formatdrop down list allows you to select any of the predefined standard formats shown above.This dialog box also allows you to easily set such properties as PromptChar, ClipMode,and MaxLength.

A MaskedEdit field can have a maximum of 64 characters (the valid range is 1 to 64characters). This includes literal characters as well as mask characters. You can set thisvalue using the MaxLength property. At design time, this property is set automatically tothe number of characters in the pattern when you enter a mask pattern.

The ClipMode property specifies whether or not literal characters are included when doinga cut or copy command. By default, when a selection in the MaskedEdit control is copiedto the Clipboard, the entire selection, including the literals, is transferred. To limit the copyoperation to only the data entered by the user, set the ClipMode property to True.

The ValidationError Event

The ValidationError event occurs when the MaskedEdit control receives invalid input, asdetermined by the input mask. For example, if you've defined an input mask that promptsfor numbers, a ValidationError event will occur if the user attempts to enter a letter.Unless you write an event handler to respond to the ValidationError event, the

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 78: VB12

MaskedEdit control will simply remain at the current insertion point — nothing willhappen.

Mask characters are validated as they are entered and the insertion point is shifted to theright. When a character is entered or deleted out of sequence (when a digit is inserted ordeleted after the phone number has been entered, for example), all nonliteral charactersshift either to the right or left. When the shift occurs, if an invalid character replaces theposition of a valid character, the ValidationError event is triggered.

For example, suppose the Mask property is defined as "?###", and the current value of theText property is "A12." If you attempt to insert the letter "B" before the letter "A," the"A" would shift to the right. Since the second value of the input mask requires a number,the letter "A" would cause the control to generate a ValidationError event.

The MaskedEdit control also validates the values of the Text property at run time. If theText property settings conflict with the input mask, the control generates a run-time error.

You can select text in the same way you would with a standard text box control. Whenselected text is deleted, the control attempts to shift the remaining characters to the rightof the selection. However, any remaining character that might cause a validation errorduring this shift is deleted, and no ValidationError event is generated.

Using MaskedEdit as a Bound Control

The MaskedEdit control is a bound control. This means that it can be linked to a datacontrol and display field values for the current record in a data set. The MaskedEditcontrol can also write out values to a data set.

Note When the value of the field referenced by the DataField property is read, it isconverted to a Text property string, if possible. If the recordset is updatable, the string isconverted to the data type of the field.

The MaskedEdit control has three bound properties: DataChanged, DataField, andDataSource.

To Pause your application for a length of time without a timer controlBy Danny K [email protected]

First put this code either in a module as a private function on a form

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

Then when you want to pause something just do this

Sleep 1000 'Pause for 1 second

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 79: VB12

LAZY BOYS SCREENSAVERBy Jyothish [email protected] neat little utility called VBCAMERA.OCX. You just load the component and place it inyour form. It will take the photograph of the running screen.VBCAMERA.OCX </vb-mag/0010/item/vbcamera.ocx>VBTalk.OCXBy Jyothish [email protected] is an innovative OCX with a beautifully shaded background, in which you can typeanything. The OCX will make the computer say the same thing that is in the textbox.VBTalk1.OCX </vb-mag/0010/item/vbtalk1.ocx>Function to Retr ieve a Standard Recordset Object.By Ray [email protected]: VB5 / VB6 / ADOMost of my application require extensive use of recordsets. I found myself writing thesame "with" construct over and over again. To save some time, I built the followingfunction to return a recordset object I can use in any situation:'**************************************************************************'Function: GetRSTemplate''Description: Builds an empty recordset to return to the calling' procedure. This is used to initialize a default recordset, yet allow' the user to change default cursor parameters at this time''**************************************************************************Function GetRSTemplate(Optional eCurLoc As CursorLocationEnum, _ Optional eCurType As CursorTypeEnum, _ Optional eLockType As LockTypeEnum) As ADODB.Recordset

Dim rsholder As New ADODB.Recordset

'If the user does not include a parameter use defaults.'The default recordset sets up a static, client side cursor with'minimal locking

With rsholder If eCurLoc = 0 Then .CursorLocation = adUseClient Else .CursorLocation = eCurLoc End If If eCurType = 0 Then .CursorType = adOpenStatic Else .CursorType = eCurType End If If eLockType = 0 Then

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 80: VB12

.LockType = adLockBatchOptimistic Else .LockType = eLockType End IfEnd With

Set GetRSTemplate = rsholder

Set rsholder = Nothing

End Function

Using it is very simple. If you supply no paramters, you get a client side, static cursor withminimal locking:

Private sub command1_click()

Dim rs as new ADODB.Recordset

set rs = GetRSTemplate()

end sub

The function uses the same enumerated values as the recordset properties, so the choiceswill pop up as they do when you type in object.property =Determines the number of workdays within a date range.By Bill [email protected] used implicit If Statements (IIF) because they take less lines of code, and this procedureis convoluted enough without making is bigger! In case you aren't familiar with them, theyare a hold-over from VBA. The first argument is the expression, the second is what to doif it's true, the third is what to do if it's false.The first part determines the number of days between 2 dates. The second part determinesthe number of whole weeks because each whole week has a Saturday & a Sunday in it.The last part determines if the range spanned a weekend but not a whole week so it cansubtract the weekend out.Private Sub FindWorkDays() Dim A1 As Date Dim A2 As Date Dim iWorkDays As Integer

A1 = Text1.Text A2 = Text2.Text

iWorkDays = A2 - A1 + 1 - Int((A2 - A1 + 1) / 7) * 2 - _ IIf(Int((A2 - A1 + 1) / 7) = (A2 - A1 + 1) / 7, 0, _ IIf(WeekDay(A2) < WeekDay(A1), 2, 0)) - _ IIf((WeekDay(A1) = 1 Or WeekDay(A2) = 7), 1, 0)

Label1.Caption = iWorkDays

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 81: VB12

End Sub

An Elliptical Command Button.By Jyothish [email protected] is an OCX file (JYOT.ZIP) which is a command button in an elliptical shape. Youcan use this control without writing code for getting this elliptical shape.

JYOT.ZIP </vb-mag/0001/item/jyot.zip>Display a Form without a Titlebar .By January [email protected], an application needs a special window without a title bar, the horizontal bar at thetop of a window that contains the title of the window. For instance, a splash screen or acustom context sensitive menu are nothing more than VB forms without title bars. Tomake a form appear without a title bar set the following design-time and run-timeproperties.Properties that must be set at design-time, they are read-only atrun-time:

ControlBox=False ' Turns off Control-menu: Restore, Move, Size,Minimize, Maximize, Close

MaxButton=False ' Turns off Maximize buttonMinButton=False ' Turns off Minimize buttonShowInTaskbar=False ' Hides window in Taskbar

Properties that can be set at either run-time or design-time:Caption="" ' Blanks window title

Making a form invisible, but leaving the controls visible.By Nigel [email protected] involves using the SetWindowLong API function with the following parameters,GWL_EXSTYLE and WS_EX_TRANSPARENT as constants.

the syntax of the function using the paramters is

dim intresult as long

intresult = setwindowlong(me.hwnd, gwl_exstyle, ws_ex_transparent)

this will make the form referenced by me.hwnd transparent so that the background can beseen but the controls can still be accessed.Making a form stay on top.By Nigel [email protected] one is for VB programmers who enjoy VB but are new to Visual Basic.Create a Module called ontop.bas in this module put the following constants.

Public Const HWND_NOTOPMOST = -2

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 82: VB12

Public Const HWND_TOPMOST = -1 Public Const SWP_NOMOVE = &H2 Public Const SWP_NOSIZE = &H1

Declare Function SetWindowPos Lib "user32" (ByVal hwnd as long, ByVal hWndInsertAfter as long, ByVal x as long, ByVal y as long, ByVal cx as long, ByVal cy as long, ByVal wFlags as long) as Long

In the General declarations of the form (ontop.frm) declare a variable lngontop as long

Put two command buttons on the form,

command1.caption = &SetOnTop command2.caption = &Make Normal

Code for command1

Private Sub Command1_Click()

lngontop = SetWindowPos = (me.hwnd,HWND_TOPMOST,0,0,0,0,(SWP_NOMOVE or SWP_NOSIZE))

End Sub

Code for command2

Private Sub Command1_Click()

lngontop = SetWindowPos = (me.hwnd,HWND_NOTOPMOST,0,0,0,0,(SWP_NOMOVE or SWP_NOSIZE))

End Sub

The Command1 button set the Always On Top behaviour of the form, while Command2sets it back to normal.Number of Workdays between two dates.By Bill [email protected] stumbling around with case statements, tons of if statements I finally found the codeto get the number of Workdays between two dates, & it only takes a few lines of code.Anyway, here is the code that Excel uses for its NetWorkdays function, and the code imodified to fit VB:Excel=A2-A1+INT((A2-A1+1)/7*2-IF(INT((A2-A1+1)/7)=(A2-A1+1/7,0,IFWEEKDAY(A2)<WEEKDAY(A1),2,0))-IF(OR(WEEKDAY(A1)=1, pre <lblDays.Caption="intDaysBetween" 0) 1, WeekDay(EndDate)="7)," Or IIf((WeekDay(StartDate)="1" - _0)) 2, WeekDay(StartDate), IIf(WeekDay(EndDate) 0, 7, 1) + StartDate 7)="(EndDate" IIf(Int((EndDate 2* 7 Int(EndDate 1 intDaysBetween Date As EndDate Dim Integer VB WEEKDAY(A2)="7),1,0)"As you can see i had to replace all the IF's with IIf's (implicit If's). Thefirst part determines the number of days between the 2 dates. The next part

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 83: VB12

determines the number of whole weeks between because of the Saturdays &Sundays. Then the last part determines if the dates spanned a weekend wherethe start date day would be smaller that the end date day.

Lostfocus of a text box control.

By [email protected] tip is w.r.t the problem of going in a loop when performing validation on the lostfocus of a text boxcontrol.

I have seen that many programmers face this problem and to solve this problem VB 6.0 has introduced aValidate event also.But as i have been using VB 4.0 from a long time i have found a simpler trick to handle this problem,which works on VB 4.0 and VB 6.0

Place two text boxes on the form and see that the initial text property is blank.

Paste the following code on the form:

Private Sub Text1_LostFocus() If Val(Text1.Text) > 0 Then Text1.SetFocus MsgBox "Value cannot be greater than zero." End IfEnd Sub

Private Sub Text2_LostFocus() If Val(Text2.Text) = 0 Then Text2.SetFocus MsgBox "Value cannot be equal to zero." End IfEnd SubAnd now run the application. Type some value in text1 and do a lostfocus and everything will work fine.Now change the code and do a setfocus after the message is displayed on the lostfocus of both the textboxes. That is change the code to :Private Sub Text1_LostFocus() If Val(Text1.Text) > 0 Then MsgBox "Value cannot be greater than zero." Text1.SetFocus End IfEnd Sub

Private Sub Text2_LostFocus() If Val(Text2.Text) = 0 Then

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 84: VB12

MsgBox "Value cannot be equal to zero." Text2.SetFocus End IfEnd SubNow run the application.Type some value in the first text box and perform a lostfocus and you will seethat everything goes in a loop and the only solution is to perform an abnormal termination of theapplication..Hence the trick is that if any validation is to be done and you need to place the control back on the textbox then perform a setfocus before the Message is displayed instead fo performing it after the message isdisplayed.

Map and Disconnect network dr ive letter .By Keith Keller [email protected] really think VBers will like this little application. It answers several questions:

How can I map a networked Drive LetterHow can I disconnect a networked Drive LetterHow can I Open a file or application with VB without using the limited "SHELL" command

I have included the compiled app and its source code. You will need VB6 to open this project, but it will workin any version of VB from 32-bit 4.0 on up!

Invalid use of null er ror .By John Wr [email protected] nice way to avoid the 'invalid use of null' error is to use the VB build in function VarType. Use thefollowing code to check for the vartype:dim retvaldim retvaltype

'add code to retrieve information from the recordset and assign it to the retval

retvaltype = VarType(retval)

if retvaltype = 2 then retval = "" ' or you could put a 0(zero) if it is a numeric fieldelse reval = retvalend ifThis should be done only with small amount of variables declared as variant as it take more overhead todelcare a variant, however if you need a fast way to solve this problem it works.

How to create dll files using Visual Basic.By Ahmed Zulfiqar [email protected] level of VB knowledge required. VB4/5/6It is always said that the only language for creating dll is C or C++, but VB is also very powerful and easyto use for the creation of dll files. Here is a sample of how u can create a small message dll file and thencall it in your program, the way you call windows dll.Open a new ActiveXDll project from New Project Menu in VB. change the name of class1 to message andset the following properties asProperties of class Message

Name MessageDataBindingBehavior 0-VBNoneDataSourceBehavior 0-VBNone

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 85: VB12

Instancing 5-MultiuseMTSTransactionMode 0-NotAnMTSObjectPersistable 0-NonPersistableThere are four public proceudres for message dialogue box. You can write any type of procedure orfunction, but for simplicity I wrote procdures that only display message boxes.Public Sub information(details, title)MsgBox details, vbInformation, titleEnd Sub

Public Sub exclaim(details, title)MsgBox details, vbExclamation, titleEnd Sub

Public Sub question(details, title)MsgBox details, vbQuestion, titleEnd Sub

Public Sub critical(details, title)MsgBox details, vbCritical, titleEnd SubFrom the File menu, choose Make Project1 Dll.. Since we haven't change the name of project, the defaultname is project1. save the program.Now open a new project in VB. Go to the Project Menu and choose References and check the Project1 asshown below.Create a form and place two text boxes on that form. Name them txtDescription and txtTitle. Also placefour Option button on the form and name them, optInformation, optQuestion, optCritical, and optexclaimand a command button name cmdRun as shown

Option ExplicitPrivate mess As New message

Private Sub cmdRun_Click()

If optInformation = True Then mess.Information txtDescription, txtTitleElseIf optQuestion = True Then mess.question txtDescription, txtTitleElseIf optCritical = True Then mess.critical txtDescription, txtTitleElse mess.exclaim txtDescription, txtTitleEnd If

End Sub

Now write some text in description box and the title text in title text box and also choose the message typeand press the command button and u will see the appropriate message coming through the dll file.

Find the number of workdays between two dates.By High Tree Soft - Warnsveld, The Nteher [email protected] Bill Mosca, I had to find the number of workdays between two dates. This solution doesn’ t haverules, the starting day may be any day of the week. Workdays are Monday through FridayPut two textboxes and a command button on a form, and call them;

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 86: VB12

txtDagenData2wdHere’s the code I came up with:Please Note: Code in dutchPrivate Sub wd_Click()If Not IsDate(txtDagen.Text) Then MsgBox "U moet een datum invullen ( Datum 1 )" txtDagen.Text = "" Exit Sub

End If

If Not IsDate(Data2.Text) Then MsgBox "U moet een datum invullen ( Datum 2 )" Data2.Text = "" Data2.SetFocus Exit Sub

End If'================Dagnummer$ = ""zat$ = ""bij$ = ""Dagnummer1$ = ""Dagnummer2$ = ""Rekendagen$ = ""Verschil$ = ""weken$ = ""Overdagen$ = ""aww$ = ""odb$ = ""Weekdagen$ = ""awr$ = ""aftel$ = ""Werkdagen = ""

Verschil$ = DateDiff("d", txtDagen.Text, Data2.Text, 2)Dagnummer$ = DatePart("W", txtDagen.Text, 2)Dagnummer2$ = DatePart("W", Data2.Text, 2)

Overdagen$ = Format$(7 - Val(Dagnummer$))Rekendagen$ = Format$(Val(Verschil$) - Val(Overdagen$))weken$ = Format$(Int(Val(Rekendagen$) / 7))

Weekdagen$ = Format$(Val(Rekendagen$) - (7 * Val(weken$)))

aww$ = Format$(Val(weken$) * 5)awr$ = Format$(Val(aww$) + Val(Weekdagen$))

'========

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 87: VB12

If Val(Dagnummer$) = 6 Then odb$ = Format$(Val(Overdagen$) - 1) aftel$ = "1"ElseIf Val(Dagnummer$) = 7 Then odb$ = Format$(Val(Overdagen$) - 0) aftel$ = "0"Else odb$ = Format$(Val(Overdagen$) - 2)End If'==========

If Val(Dagnummer2$) = 6 Then zat$ = "-1"Else zat$ = "0"End If

If Val(Dagnummer$) = 6 Or Val(Dagnummer$) = 7 Then bij$ = "0" Werkdagen = Format$(Val(awr$) + Val(odb$) + Val(zat$))Else bij$ = "1" Werkdagen = Format$(Val(awr$) + Val(odb$) + Val(bij$) + Val(zat$))End If

'==================

MsgBox "Aantal werkdagen = " & Werkdagen

End Sub

This function checks the validity of a credit card number .By James [email protected] 'True' If the number is in a valid format.Returns 'False' If the number is in an invalid format.Descr iption:This algorithm should work with all credit cards.If a card validates with this code it doesn't mean that the card is actually good, it just means that thenumbers are arranged in a valid format. If they don't validate then you've saved some time because youdon't have to process the card to find out that it is defiantely bad. I use this function in CGI forms thatprocess credit card orders.Function CheckCard(CCNumber As String) As Boolean Dim Counter As Integer, TmpInt As Integer Dim Answer As Integer

Counter = 1 TmpInt = 0

While Counter <= Len(CCNumber) If (Len(CCNumber) Mod 2) Then TmpInt = Val(Mid$(CCNumber, Counter, 1)) If Not (Counter Mod 2) Then

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 88: VB12

TmpInt = TmpInt * 2 If TmpInt > 9 Then TmpInt = TmpInt - 9 End If Answer = Answer + TmpInt Counter = Counter + 1 Else TmpInt = Val(Mid$(CCNumber, Counter, 1)) If (Counter Mod 2) Then TmpInt = TmpInt * 2 If TmpInt > 9 Then TmpInt = TmpInt - 9 End If Answer = Answer + TmpInt Counter = Counter + 1 End If Wend

Answer = Answer Mod 10

If Answer = 0 Then CheckCard = TrueEnd Function

Making a Gr id Auto-ResizeBy Richard Rober [email protected] problem with the Grid control in VB5.0 is that there is no property to force it to auto-resize thecolumn width. So I wrote this little function that accepts the form name that the grid is on and the nameof the grid. The function then loops through the grid and resizing each column width to the widest textentry in that column.GRID.FRM </vb-mag/9812/item/grid.frm>

Find the number of workdays between two datesBy Bill [email protected] had to find the number of workdays between two dates (including Saturday as a possible starting day).The number of days were grouped into these ranges: 1 day, 2 days, 3 days, 5+days, 10+days, and 30+days.The rules were No input on Sundays and starting dates were only Monday through Friday, but endingdates might be on Saturdays. Here's the code I came up with: Select Case DaysBetween Case 0 To 6 Select Case DaysBetween Case 0, 1 rs.Edit rs("Days") = 1 rs.Update Case 2 rs.Edit rs("Days") = 2 rs.Update Case 3 If WeekDay(Date2) = vbMonday Then rs.Edit rs("Days") = 1 rs.Update Else rs.Edit

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 89: VB12

rs("Days") = 3 rs.Update End If Case 4 If WeekDay(Date2) = vbMonday Then rs.Edit rs("Days") = 2 rs.Update ElseIf WeekDay(Date2) = vbTuesday Then rs.Edit rs("Days") = 3 rs.Update Else rs.Edit rs("Days") = 3 rs.Update End If

Case 5 '5 to 9 -->5+ If WeekDay(Date2) < vbFriday Then rs.Edit rs("Days") = 3 rs.Update ElseIf WeekDay(Date2) >= vbFriday Then rs.Edit rs("Days") = 5 rs.Update End If Case 6 If WeekDay(Date2) < vbThursday Then rs.Edit rs("Days") = 3 rs.Update ElseIf WeekDay(Date2) >= vbThursday Then rs.Edit rs("Days") = 5 rs.Update End If End Select Case 7 To 11 '5 to 9 -->5+ rs.Edit rs("Days") = 5 rs.Update Case Is > 11 WeeksBetween = DateDiff("w", Date1, Date2) Select Case WeeksBetween Case 1 To 5 '10 to 29 -->10+ rs.Edit rs("Days") = 10 rs.Update Case Is > 5 '30+ rs.Edit rs("Days") = 30 rs.Update

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 90: VB12

End Select End Select Else 'if bill is a Send Back rs.Edit rs("Days") = 0 rs.Update End If rs.MoveNext Loop

Return True if no value is passedBy Sentil Kumar [email protected] you use a typed variable as optional argument in a Function or Sub you can't use "ISMISSING" functionto determine whether it is initialized or not.To solve this you can use "Empty" keyword as follows, Public Function MyFun (Optional ByVal sOptVaras String) As Boolean if sOptVar = Empty then MyFun = True

Else MyFun = False End if End FunctionThis function returns True if no value is passed to the optional variable sOptVar, else returns False.This Works in VB5.0.

Call a value from your enumerationBy Marcio [email protected] talks about "How useful enumeration is". Here goes a little piece of code that reallydemonstrates that statement is correct.With a little help from a property let and property get, you can call a value from your enumeration withouthaving to remember the description you previouslly coded inside of your enumeration since it will pops upfor you.* Here goes the code:'Add this code to a module.basDim mForm As ByteEnum FromForm FormNameA = 1 FormNameB = 2 FormNameC = 3End Enum

Property Get SetForm() As FromForm SetForm = mFormEnd Property

Property Let SetForm(Value As FromForm) mForm = ValueEnd Property

'Add this to a command button on your application'to associate with a formSetForm = FormNameB

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 91: VB12

Snds parameters in an INDEX format to a classBy Marcio [email protected] are developing a crystal report print engine dll, that will be called from another dll, and will generatereports.On the first tier, we want to pass the report parameters to the second tier. Although we know we can dothat on an array manner, we found out that sending the parameters in an INDEX manner should make theprocess much more friendly for the first tier developer. Therefore, the code bellow, sends parameters in anINDEX format to a class. When the class receives the parameters, it builds an array that can be used inthe class as desired.On the first tier the code is something like the one bellow.* After referencing the DLL or making a class named PrintEngineDim ObjPrint as PrintEngine.EngineSet ObjPrint = New EngineobjPrint.StoreProcParam(0) = Variable 1objPrint.StoreProcParam(1) = Variable 2objPrint.StoreProcParam(2) = Variable 3objPrint.StoreProcParam(3) = Variable 3and so on......On second tier the code is something like the one bellow.Private mStoreprocparam() As VariantPublic Property Let StoreProcParam(Index As Integer, value As String)

ReDim Preserve mStoreProcParam(Index)Let mStoreProcParam(Index) = Value

End propertyThen I use the variant mStoreProcParam on the second tier to work with the received parameters.The main point for the sample above is the property Let StoreProcParam(Index As Integer, value AsString). This property receives one index and one value at a time and stores it in the arraymStoreProcParam(). Then, that Array can be used in a lot of different ways.

How to use MSFlexGr id to display data via ADO methodBy L iu, [email protected] tried this example to show how to use MSFlexGrid to display data via ADO method, and also to showa simple SQL query. first we set up ADO object, and connected with a back end Sybase database, opened atable, which called mirtb_patient, we used a MSFlexGrid for 25 columns(fields), and specified two loops,variable ii for row(record), oo for column. This prepared query can get the data from a Sybase via ADO,and dispaly them on the MSFlexGrid. Notice that when it finish, all opening objects and methods shouldbe closed.

Option ExplicitDim Cn As New ADODB.ConnectionDim rs As ADODB.Recordset

'Use a connecting string or Connection object here

Dim sSQL As StringDim sOut As String

Private Sub connect_cmd_Click()

' Set ii as the row counter

Dim ii As Long

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 92: VB12

' Set oo as the column counter

Dim oo As Integer

'ADO Demo, it populates data with MSFlexGrid !

If Cn.State = adStateOpen Then MsgBox "ADO Connection Successful!"End If

' Set up SQL calling

sSQL = "Select * from mirtb_patient"rs.Open sSQL, Cn, adOpenDynamicsOut = ""

ii = 0

' To see if end of the table?While rs.EOF <> TrueDBGrid1.Rows = ii + 1iii = 1

' Loop for the column, we just used 25 columns for display!

For oo = 0 To 24DBGrid1.TextMatrix(ii, oo) = rs.Fields(oo)Next ooii = ii + 1

' Move to next record

rs.MoveNextWendEnd Sub

Private Sub Form_Load()

'Define a Command object for the connection

Set Cn = New ADODB.ConnectionSet rs = New ADODB.RecordsetCn.ConnectionString = "DSN=TESTRCH01;UID=ADOTRY;PWD=ADOTRY;"Cn.ConnectionTimeout = 100Cn.OpenEnd Sub

Private Sub quit_cmd_Click()

' To close objects rs and cn etc., they shoud be closed here!

rs.Close

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 93: VB12

Set rs = NothingCn.CloseSet Cn = NothingUnload MeEnd Sub

Quick single line toggle for 1/0-type boolean valuesBy Sean C. NicholsThis is for toggling boolean values that flip between 1 and zero as opposed to -1 and zero, which are VB'sbuilt-in boolean values.One common place I use it is toggling checkboxes/checkable menu options. Both of these use as their"checked" status either vbUnchecked (0) or vbChecked (1).The standard method for toggling these is to use an If-Then statement:if check_value = vbChecked Then check_value = vbUncheckedElse check_value = vbCheckedEnd IfThere is nothing inherently wrong with this, except that it takes up 5 lines of code, and the alternative ofputting it on one line, separated by colons is messy. This means extra scrolling space which can be ahindrance, especially if you have already long procedures.Unfortunately, you can't use the Not operator as in:

check_value = Not check_valuebecause Not (0) is -1, and worse, Not (1) is -2. This problem arises because the Not() function performs abitwise NOT, rather than a true logical NOT. As a result, this only works with "true" boolean values (-1/0).The solution which hit me is simply to add 2:

check_value = (Not check_value) + 2hey... works like a charm!

How to save a brande new WAV file using mciSendStr ing APIBy Pranay Uppulur iPRUppL2aol.comShows you how to save a brand new WAV file using the mciSendString API (Doen't use the MCI Controlthat comes with VB5!) It is really easy to do that. I learned it after studying this API for a while. I couldn'tget the MCI Control to save a WAV file though! I don't know why! If any body could, just e-mail it to meand I will see how it is possible to do. :-)DownloadWAVESAVE.ZIP <wavsave.zip> (File size 1.4K)

Making the Close button (X) on a form disabledBy Pranay Uppulur iPRUppL2aol.comEver wonder how those Setup programs have their X button on caption bar disabled, so you can't closethem? Well, now you can do it, when you download this!DownloadCANTCLOS.ZIP </vb-mag/9808/item/cantclos.zip> (File size 1.7K)

Even or Odd - UpdateBy [email protected] tip featured in your current issue to tell if a number is even or odd, works v_e_r_y slow. It does a lot oftype conversion between numbers and strings and unnecessary, slow string manipulation. It willremarkably slow down the machine if used in a loop and uses a dirty kind of type casting because aninteger value is used as a return value of a boolean type function (!). In addition, it will only work withVisual Basic.

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 94: VB12

There are at least two much more efficient and simple ways to tell if a number is odd or even; bothexamples will store "TRUE" in the variable "bool_IsEven" if the number is even and will work in nearlyall programming languages:

a) bool_IsEven = int_Number MOD 2 = 0 b) bool_IsEven = int_Number AND 1 = 0

How to disable Ctr l Alt Del.By Bob [email protected] Windows 95 it is possible to disable CTRL-ALT-DEL, CTRL-ESC and ALT-TAB by claiming to bethe current screen saver. Sample code can be found at http://www.vbonline.com/vb-mag/qaweb/win95/cad.htm in the new qaweb section of VB Online Magazine. To start an application youhave a few options. Normally the Startup group is used, but since this sort of application must beinaccessible to the general user you need to place it in the registry. There are three keys of interest:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunHKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceHKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices

All entries under these three keys are started during the bootup process and your application should belisted under one of them. The "Run" key names applications to run every time, as does the "RunServices"key. The difference is when they start during the boot process. You probably want to use the Run key, butyou can try both and see what the difference is. The RunOnce key will run the next time Win95 starts, butis then purged. This is a good place to put applications that complete a setup process or a cleanup.

List Box To L ist Box - VB5 ProfessionalBy Peter [email protected] is another way to move data from one list box to another and back. The four buttons ( ADD, ADDALL, REMOVE and REMOVE ALL) are a control array and the subroutine FourButtons handles allmovements between the two list boxes. I tried to use the least amount of code. This app is an unattendedbulk printing app.

Private Sub FourButtons(ByVal Index As Integer)Screen.MousePointer = 11Select Case Index Case 0 ' Add selected contractId from List1 to List2 If List1.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List1.ListIndex = -1 Then 'nothing is selected List1.SetFocus List1.Selected(0) = True 'select the first item in the list. End If DoEvents List2.AddItem List1.Text List1.RemoveItem List1.ListIndex

Case 1 ' Add All ContractIds from List1 to List2 If List1.ListCount = 0 Then

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 95: VB12

Screen.MousePointer = 0 Exit Sub End If If List1.ListIndex = -1 Then List1.SetFocus List1.Selected(0) = True End If DoEvents For i = (List1.ListCount - 1) To 0 Step -1 List2.AddItem List1.List(i) DoEvents Next i List1.Clear

Case 2 ' Remove selected contractId from List2 to List1 If List2.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List2.ListCount = 0 Then Exit Sub If List2.ListIndex = -1 Then List2.SetFocus List2.Selected(0) = True End If

List1.AddItem List2.Text List2.RemoveItem List2.ListIndex

Case 3 ' Remove All ContractIds From List2 to List1 If List2.ListCount = 0 Then Screen.MousePointer = 0 Exit Sub End If If List2.ListCount = 0 Then Exit Sub If List2.ListIndex = -1 Then 'nothing is selected. List2.SetFocus 'set focus. List2.Selected(0) = True 'select first item in list. End If For i = (List2.ListCount - 1) To 0 Step -1 List1.AddItem List2.List(i) DoEvents Next i List2.Clear

End SelectScreen.MousePointer = 0End Sub

How to wr ite a Screen Saver .By Bob [email protected] basic requirements for creating a screen saver are:

In the properties for your application set the title to:

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 96: VB12

SCRNSAVE: name

The 'name' part will appear on the list of available screen savers in the control panel. Note thatthis is not the title of the form, it is the application title and must be set in the project properties.

When you compile the program use .SCR for the extension instead of .EXE as normal. Place thecompiled code in the Windows\System directory (it can also go in Windows, but System ispreferred)

When your application starts check for a previous instance and stop if one is found:

Sub Form_Load() If App.PrevInstance Then Unload Me ' NEVER use END! Exit Sub End If

End Sub

Check the command line for switches:

/s setup mode - display/update configuration options only /p nnn preview mode - "nnn" is a handle to the preview window /a password support check

If the screen saver is to run normally use the following to tell Windows that you are taking over as ascreen saver (this will disable ALT-TAB and CTRL-ALT-DEL and prevent more instances frombeing started):

Private Const SPI_SCREENSAVERRUNNING=97 Private Declare Function SystemParametersInfo Lib "user32" _ Alias "SystemParametersInfoA" (ByVal uAction As Long, _ ByVal uParam As Long, lpvParam As Any, _ ByVal fuWinIni As Long) As Long SystemParametersInfo SPI_SCREENSAVERRUNNING, 1, ByVal 1&, FalseBefore your code terminates tell Windows you are leaving with: SystemParametersInfo SPI_SCREENSAVERRUNNING, 0, ByVal 1&, False

For more information, including sample code that handles password protected screen saverscheck http://www.arcatapet.com/vb.html or http://www.tiac.net/users/lvasseur/

reading data from a database to display on a form is null fields.By Mar tin [email protected] prevent an 'invalid use of null' error occurring when reading data from a database use the followingsyntax:

Text fields:Form1.text1.text = "" & myRecordset("TextName")

Numeric fields:Form1.Option1.Value = 0 & myRecordset("NumricField")

How to place your application in the System Tray.By James E. [email protected]

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 97: VB12

Applies to Win95 and WinNTBoth Windows95 and WindowsNT have that neat new feature called the system tray where you can placeyour application. This is easily done via the Windows API called "Shell_NotifyIcon" which manages theTaskbar which the system tray is part of.There are a couple of tricky things that you need to keep in mind when using this function. First, theapplication needs to be visible (but not necessarily seen--you can set its Top & Left to -10000) and youalso need to know how to handle callback functions. If your not sure what a callback function is then stophere (you should learn about callback functions before proceeding).First, place the declares into a bas module:' These tell you what is happening in the system tray (over your icon)Public Const WM_MOUSEISMOVING = &H200 ' Mouse is movingPublic Const WM_LBUTTONDOWN = &H201 'Button downPublic Const WM_LBUTTONUP = &H202 'Button upPublic Const WM_LBUTTONDBLCLK = &H203 'Double-clickPublic Const WM_RBUTTONDOWN = &H204 'Button downPublic Const WM_RBUTTONUP = &H205 'Button upPublic Const WM_RBUTTONDBLCLK = &H206 'Double-clickPublic Const WM_SETHOTKEY = &H32

' The API CallPublic Declare Function Shell_NotifyIcon Lib "shell32" _ Alias "Shell_NotifyIconA" _ (ByVal dwMessage As enm_NIM_Shell, pnid As NOTIFYICONDATA) AsBoolean

' User defined type required by Shell_NotifyIcon API callPublic Type NOTIFYICONDATA cbSize As Long hwnd As Long uId As Long uFlags As Long uCallbackMessage As Long hIcon As Long szTip As String * 64End Type

' This is an Enum that tells the API what to do...' Constants required by Shell_NotifyIcon API call:Public Enum enm_NIM_Shell NIM_ADD = &H0 NIM_MODIFY = &H1 NIM_DELETE = &H2 NIF_MESSAGE = &H1 NIF_ICON = &H2 NIF_TIP = &H4 WM_MOUSEMOVE = &H200End Enum

Public nidProgramData As NOTIFYICONDATA

Place this code in Form_Load():

Private Sub Form_Load()

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 98: VB12

' Hide the form With Me .Top = -10000 .Left = -10000 .WindowState = vbMinimized End With

With nidProgramData .cbSize = Len(nidProgramData) .hwnd = Me.hwnd .uId = vbNull .uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE ' This is the event that will trigger when stuff happens .uCallbackMessage = WM_MOUSEMOVE .hIcon = Me.Icon .szTip = "Lock Your System" & vbNullChar End With

' Call Notify... Shell_NotifyIcon NIM_ADD, nidProgramData

End Sub

This goes into the Form_MouseMove event:

' Name: Form_MouseMove'' Purpose: Processes the Events from the TaskBar...'' Inputs: None'' Returns: None'' Revision: James E. Bettone 12/02/1997'Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X AsSingle, Y As Single)

On Error GoTo Form_MouseMove_err:

' This procedure receives the callbacks from the System Tray icon. Dim Result As Long Dim msg As Long

' The value of X will vary depending upon the scalemode setting If Me.ScaleMode = vbPixels Then msg = X Else

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 99: VB12

msg = X / Screen.TwipsPerPixelX End If

Select Case msg Case WM_LBUTTONUP

' process single click on your iconCall Command1_Click()

Case WM_LBUTTONDBLCLK' Process double click on your icon

Case WM_RBUTTONUP' Usually display popup menu

Case WM_MOUSEISMOVING' Do Somthing...

End Select

Exit Sub

Form_MouseMove_err: ' Your Error handler goes here!

End Sub

When your Application executes, it will head right into the System Tray. It is up to you to program in thecontext menus and to process the callback messages.

Attaching and manipulating PictureBox and TextBox on the CommandButton.By JungHwan K [email protected] images are needed to be inserted at the Command Button control, there are two ways.First, the Command Button style property is set 1(Graphic) and the hape of the image can be changedaccording that the user presses the mouse button up or down. However, the images should be placed at afixed position, and both images and texts can't be displayed. Second, we can put the PictureBox which hasthe Enabled property False on the Command Button control. In this case, we can't make use of a functionof the PictureBox. That is, we can't change the BorderStyle according that the mouse pointer is in thePictureBox or out of the PictureBox. If PostMessage Windows API is used, we can solve this problem.Suppose there are two bitmap files, button.bmp and camera.bmp.Private Const WM_LBUTTONDOWN = &H201Private Const WM_LBUTTONUP = &H202Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _ ByVal lParam As Long) As Long

Private Sub Form_Load() Picture1.TabStop = False Picture1.BorderStyle = 0End Sub

Private Sub Command2_Click()

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 100: VB12

Unload MeEnd Sub

Private Sub Picture1_MouseMove(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Picture1.BorderStyle = 1End Sub

Private Sub Command1_MouseMove(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Picture1.BorderStyle = 0End Sub

Private Sub Command1_MouseDown(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Form1.Picture1.Picture = LoadPicture("button.bmp")End Sub

Private Sub Command1_MouseUp(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Form1.Picture1.Picture = LoadPicture("camera.bmp")End Sub

Private Sub Picture1_MouseDown(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Ret = PostMessage(Form1.Command1.hwnd, WM_LBUTTONDOWN, _ wParam, lParam)End Sub

Private Sub Picture1_MouseUp(Button As Integer, _ Shift As Integer, X As Single, Y As Single) Ret = PostMessage(Form1.Command1.hwnd, WM_LBUTTONUP, _ wParam, lParam)End Sub

" ShowInTaskBar" proper ty of a VB Form at runtime.By Joe [email protected] Explicit'--------------------------------

' This code will set "ShowInTaskBar" property' of a VB Form at runtime. I haven't been able' to change this property without unloading the' form. This code could be useful when used in' conjunction with a user-chosen preference.' (Maybe you can think of a good use for it.)' Comments, improvements? Please forward to:' Joe LeVasseur'-----------------------------------------------Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" (ByVal hwnd As Long, _ ByVal nIndex As Long) As Long

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 101: VB12

Private Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" (ByVal hwnd As Long, _ ByVal nIndex As Long, ByVal dwNewLong As Long) As Long'----------------------------Private Const GWL_EXSTYLE = (-&H14)Private Const WS_EX_TOOLWINDOW = &H80'----------------------------Private Sub Form_Initialize() Call SetStyleEnd SubPrivate Sub SetStyle() Dim lWindowStyle&, lRetVal& Debug.Print Second(Now) ' 50/50 chance If (Second(Now) Mod 2) Then lWindowStyle = GetWindowLong(hwnd, GWL_EXSTYLE) lWindowStyle = lWindowStyle And WS_EX_TOOLWINDOW lRetVal = SetWindowLong(hwnd, GWL_EXSTYLE, lWindowStyle) End IfEnd Sub

Delaying a VB app for a set number of M inutes, Seconds.By Joe [email protected] ExplicitDim StopTheTimer As Boolean

Private Sub Command1_Click() Dim lRetval& lRetval = Delay(1, 5, StopTheTimer) If lRetval = 0 Then MsgBox "Time's up!" Else MsgBox "You cancelled!" End IfEnd SubPrivate Sub Command2_Click() StopTheTimer = TrueEnd Sub

Public Function Delay(Mins%, Secs%, Optional ByRef StopFlag) As Long Dim EndOfDelay EndOfDelay = DateAdd("n", Mins, Now) EndOfDelay = DateAdd("s", Secs, EndOfDelay) Delay = 0 Do While (Now < EndOfDelay) DoEvents If Not IsMissing(StopFlag) Then If StopFlag Then Delay = 1 StopFlag = False Exit Do End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 102: VB12

End If LoopEnd Function

Easy Transparent Scrolling text on pictureBy Antonio [email protected] idea is from the scrolling text I read in a old "tips&tricks" and part of the listing is from it. Create aform and load on it a <<.bmp>> picture, by picture property. Create a label and a timer on the form. Theproperties of the label you must change are BackStyle=3D0 transparent and borderstyle 0=3DNome. Thentype the statements in the subs:Sub Form_Load()Me.ShowLabel1.Caption =3D "Hi!! scroll Test.."Label1.ForeColor =3D &HFFScaleMode =3D 3 theleft =3D ScaleWidth / 2

thetop =3D ScaleHeight

Timer1.Enabled =3D True Timer1.Interval =3D 10End Sub

Sub Timer1_Timer()Label1.Top =3D thetop thetop =3D thetop - 1 If thetop < -p1hgt Then Timer1.Enabled =3D False Txt$ =3D "Finished With Scrolling" CurrentY =3D ScaleHeight / 2 CurrentX =3D (ScaleWidth - TextWidth(Txt$)) / 2 Print Txt$ End IfEnd Sub

No L istbox.ScrollPos member?By Dave [email protected] working on a current project the requirement to scroll an array of listboxes simultaneously croppedup. I was surprised to discover that there is no Listbox.ScrollPos member of the ListBox control and sohad to resort to the windows API to overcome this oversight. The results of which are included below.Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwndAs Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long

' *** ListBox Scroll Event ***Private Sub lst_Ranges_Scroll(Index As Integer)Dim I As Integer, Pos As IntegerStatic bScrolling As Boolean

If Not bScrolling Then bScrolling = True Pos = GetScrollPos(lst_Ranges(Index).hwnd, SB_VERT) For I = 0 To 3

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 103: VB12

If I <> Index Then SendMessage lst_Ranges(I).hwnd, WM_VSCROLL,MakeLong(SB_THUMBPOSITION, Pos), SB_THUMBPOSITION End If Next bScrolling = FalseEnd IfEnd Sub

' *** MakeLong Method ***Private Function MakeLong(LOWORD As Integer, HIWORD As Integer) As LongMakeLong = Bitwise_OR(LOWORD, Bitwise_SHL(HIWORD, 16))End Function

I hope this will be of some use to somebody someday, I know that I was surprised when I discovered thelack of a ScrollPos Member.

The " AlwaysOnTop" proper ty.By Joe [email protected] paste the code below into the form that you need to have the "AlwaysOnTop" property. Syntaxwould be like this-[FormName].AlwaysOnTop= True Note the commented code in the Resize event, theform loses the "AlwaysOnTop" property if it is minimized. I think that under most circumstances a"AlwaysOnTop" window would probably be a fixed dialog and therefore not minimizable. One othercaveat- this code may or may not work in the IDE. (I've seen both.)__________snip____________________________________Option Explicit'------------------' Paste this into a form and you' will have a new property-AlwaysOnTop.' You then can use it like any other' property- [FormName].AlwaysOnTop= True' Joe LeVasseur'------------------Private Const HWND_TOPMOST = -&H1Private Const HWND_NOTOPMOST = -&H2Private Const SWP_NOSIZE = &H1Private Const SWP_NOMOVE = &H2'------------------Private Declare Sub SetWindowPos Lib "user32" (ByVal hWnd As Long, _ ByVal hWndInsertAfter As Long, ByVal x As Long, _ ByVal y As Long, ByVal cx As Long, ByVal cy As Long, _ ByVal wFlags As Long)'------------------Private bOnTopState As BooleanPublic Property Let AlwaysOnTop(bState As Boolean) Dim lFlag As Long On Error Resume Next If bState = True Then lFlag = HWND_TOPMOST Else lFlag = HWND_NOTOPMOST End If bOnTopState = bState

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 104: VB12

Call SetWindowPos(Me.hWnd, lFlag, 0&, 0&, 0&, 0&, _ (SWP_NOSIZE Or SWP_NOMOVE))End PropertyPublic Property Get AlwaysOnTop() As Boolean AlwaysOnTop = bOnTopStateEnd Property'------------------Private Sub Form_Resize()' Only need this if form can be' minimized.(Loses the setting.) 'AlwaysOnTop = bOnTopStateEnd Sub_________snip___________________________________________

Here's a another way to speed up looping through a recordsetBy Jeff [email protected] was a good tip for speeding up looping through a recordset in this tips section. (I have included itbelow for reference) However, if you have the option, there is another way to perform an operation onevery member of a recordset that will execute much faster than any recordset operation, use a SQLUPDATE statement to modify the records. That way, the modification executes on the database server,and gets whatever optimizations your database engine provides. For example, to give all yourlongstanding customers a discount, you could use the following SQL statement in place of any recordset:

UPDATE Customers SET Discount = 0.10 WHERE CustSince <= 1993This could take the place of getting a recordset with the SQL:SELECT Discount FROM Customers WHERE CustSince <= 1993and then needing to navigate the whole recordset setting each Discount to 10%.

--------------------------------------------------------------------------------------------------------------------------------------Accessing Databases

This tip is on accessing databases. For performing an operation inevery record of a Table or RecordSet (for example you could want to update some fields, or retrieve some information), generallythis code is used.

Do ... ... MyDynaset.MoveNext Loop Until MyDynaset.EOF

Bat if you use this code

Dim k As Long, j As Long

MyDynaset.MoveLast j = MyDynaset.RecordCount MyDynaset.MoveFirst

For k = 1 to j ... ... MyDynaset.MoveNext Next

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 105: VB12

you should notice is 30% speed increase from the first code. I triedthis code with a MDB file with 17000 records, and with a MDB file with 500 records. They both work well. The reason? Of coursebecause the second code does not check the EOF condition every iteration (even if it must go to the last record and then to thefirst record)! Maybe, if the recordset is small you may not notice any improvement, but in this case, processing time is short anyway. Ifound this code does not improve processing time in Delphi. I think it's because Delphi EXE is compiled and not p-code.

Tip supplied by Castelli Stefano---------------------------------------------------------------------------- ----------------------------------------------------------

Here's a efficient IsEven functionBy Sam [email protected] IsEven( n as Integer) As Boolean IsEven = Not -(n And 1) End Function If you want an IsOddfunction, just omit the Not.

Move elements from one list box to anotherBy Er ic [email protected]. <mailto:[email protected]>This is something I feel a few people might find to be useful. Basically it allows elements to be movedbetween two list boxes as well as conditionally enabling an Execute button if there are any elements in thesecond list box. You should first design a form that looks like this:

Private Sub cmdLeft2Right_Click() If lstList1.ListCount > 0 Then List_Refresh lstList1, lstList2 cmdExecute.Enabled = True End If If lstList1.ListCount > 0 Then cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True Else cmdLeft2Right.Enabled = False cmdAll2Right.Enabled = False cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True End IfEnd Sub

Private Sub cmdAll2Right_Click() Move_All_Items "Right", lstList1, lstList2 cmdLeft2Right.Enabled = False cmdAll2Right.Enabled = False

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 106: VB12

cmdAll2Left.Enabled = True cmdRight2Left.Enabled = True cmdExecute.Enabled = TrueEnd Sub

Private Sub cmdAll2Left_Click() Move_All_Items "Left", lstList1, lstList2 cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True cmdAll2Left.Enabled = False cmdRight2Left.Enabled = False cmdExecute.Enabled = FalseEnd Sub

Private Sub cmdRight2Left_Click() If lstList2.ListCount > 0 Then List_Refresh lstList2, lstList1 If lstList2.ListCount > 0 Then cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True Else cmdExecute.Enabled = False cmdLeft2Right.Enabled = True cmdAll2Right.Enabled = True cmdAll2Left.Enabled = False cmdRight2Left.Enabled = False End IfEnd Sub

Public Sub Move_All_Items(Direction As String, List1 As Control, List2 As Control)Dim Count As Integer Select Case Direction Case "Left" For Count = 0 To List2.ListCount - 1 List1.AddItem List2.List(Count) List2.Selected(Count) = 0 Next Count List_Refresh List2, List1 List2.Clear Case "Right" For Count = 0 To List1.ListCount - 1 List2.AddItem List1.List(Count) List1.Selected(Count) = 0 Next Count List_Refresh List1, List2 List1.Clear End SelectEnd Sub

' Special Subroutine to move selected items from one listbox to anotherPublic Sub List_Refresh(SourceList As Control, TargetList As Control) Dim N As Integer Dim I As Integer ReDim Remove(0 To SourceList.ListCount - 1) As Boolean 'Items to remove For N = 0 To (SourceList.ListCount - 1) ' If selected, then , add to Target List

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 107: VB12

If SourceList.Selected(N) = True Then TargetList.AddItem SourceList.List(N) Remove(N) = True ' Sets item for removal from Source list End If Next N

Dim C As Integer ' Counts how many have been removed C = 0 For N = 0 To UBound(Remove) If Remove(N) Then SourceList.RemoveItem N - C C = C + 1 End If Next N

For I = 0 To (SourceList.ListCount - 1) ' Reset Selected Flags and reset SourceList.Selected(I) = False Next I SourceList.Refresh TargetList.RefreshEnd Sub

"This method is meant to work best when the multi-select feature of the listboxes is enabled"

Check a DOB against a valid ageAuthor: James JohnstonEmail : [email protected]: This function checks a DOB against a valid age.Returns 'True' if the DOB is valid for the specified age.Returns 'False' if the DOB is not valid for the specified age.I've used this in CGI programs that need DOB validation.Function CheckDOB(TestDOB As String, ValidAGE As Integer) As Boolean Dim TmpInt As Long

TmpInt = DateDiff("d", CDate(TestDOB), Now)

If TmpInt < (ValidAGE * 365.25) Then CheckDOB = False Else CheckDOB = True End If

End FunctionTip supplied by James Johnston [email protected]

Tells whether a number is even or odd.Returns 'True' if even.Returns 'False' if odd.

Function IsEven(TestInt As Integer) As Boolean Dim TestValues As String, TmpChar As String, Answer As Integer

TestValues = "02468" TmpChar = Right$(Trim(Str$(TestInt)), 1) Answer = InStr(1, TestValues, TmpChar)

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 108: VB12

IsEven = Answer

End FunctionTip supplied by James Johnston [email protected]

Accessing DatabasesThis tip is on accessing databases. For performing an operation in every record of a Table or RecordSet(for example you could want to update some fields, or retrieve some information), generally this code isused.Do ... ... MyDynaset.MoveNextLoop Until MyDynaset.EOF

Bat if you use this code

Dim k As Long, j As Long

MyDynaset.MoveLastj = MyDynaset.RecordCountMyDynaset.MoveFirst

For k = 1 to j ... ... MyDynaset.MoveNextNextyou should notice is 30% speed increase from the first code. I tried this code with a MDB file with 17000records, and with a MDB file with 500 records. They both work well. The reason? Of course because thesecond code does not check the EOF condition every iteration (even if it must go to the last record andthen to the first record)! Maybe, if the recordset is small you may not notice any improvement, but in thiscase, processing time is short anyway. I found this code does not improve processing time in Delphi. Ithink it's because Delphi EXE is compiled and not p-code.

How to implement " What's this?" HelpUnder Windows 95 and Windows NT 3.51, it is possible to right-click on items and get the "What'sThis?" window to appear. To set this up in Visual Basic, you need to use a pop-up menu.

Example• Start Visual Basic 4.0 or, if it is already running, click New Project on the File menu.

• Set the WhatsThisHelp and WhatsThisButton properties for Form1 to TRUE.

• Add the following code to reference the Hotspot Editor help file to the Form_Load procedure:Private Sub Form_Load()'This should point to the hc directory

'under the VB4 directoryApp.HelpFile = "c:vbhcshed.hlp"End Sub

• Add two menu items to Form1 using the following as a guide:Menu Property Value----------------------------------------------------WhatsThis Caption WhatsThisWhatsThis Name mnuWhatsThis

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 109: VB12

WhatsThis Visible False

What's This? Caption What's This?What's This? Name mnuWhatsThisHelp

• Indent "What's This?" to make it a sub-menu of WhatsThis by pressing the right-arrow button onthe Menu Editor.

• Add the following code to the General Declarations section of Form1:Public ThisControl as control

• Add the following code to the mnuWhatsThisHelp_Click procedure:Private Sub mnuWhatsThisHelp_Click()ThisControl.ShowWhatsThisEnd Sub

• Add a Command Button control to the form and set the following Properties:WhatsThisHelpID = 1HelpContextID = 5

• Add following code to the Command1_MouseUp event:Private Sub Command1_MouseUp(Button As Integer, Shift As Integer, _X As Single, Y As Single)If Button = vbRightButton Then Set ThisControl = Command1 PopupMenu mnuWhatsThisEnd IfSet ThisControl = NothingEnd Sub

• Run the application. Right-click on the Command button and then left-Click on the "What's This?" popup to bring upthe Help file.

Creating Rainbow TextThis week I will show you a useful tip that is very simple to do and very effective.You may have seen programs that have multicoloured (Rainbow) text in the background.Well this is very simple to do using a for loop.

Code1. Start a new Standard Exe project; form1 is created by default2. Type in the following code.Sub Form_Paint()Dim I As Integer, X As Integer, Y As IntegerDim C As StringClsFor I = 0 To 91X = CurrentXY = CurrentYC = Chr(I)'Line -(X + TextWidth(C), Y = TextHeight(C)), _QBColor(Rnd * 16), BFCurrentX = XCurrentY = YForeColor = RGB(Rnd * 256, Rnd * 256, Rnd * 256)Print "Hello World Hello World Hello World Hello"NextEnd Sub3. Run the program by pressing F5 or choosing start from the run program and watch the form fill withlots of multi-coloured text

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html

Page 110: VB12

How can I detect if the system has a sound card?A lot of programs are now playing sounds for certain events. However, there is no point in wasting timeby playing a sound if the system does not support it. This tip demonstrates how to detect if a sound cardexists.

DeclarationsAdd the following code to the declarations section of the project.Declare Function waveOutGetNumDevs Lib "winmm.dll" _Alias "waveOutGetNumDevs" () As Long

CodeDim i As Integeri = waveOutGetNumDevs()If i > 0 Then MsgBox "Your system can play sound files.", _ vbInformation, "Sound Card Test"Else MsgBox "Your system can not play sound Files.", _ vbInformation, "Sound Card Test"End If

No license: PDF produced by PStill (c) F. Siegert - http://www.this.net/~frank/pstill.html