Visual Basic

Sample Answers to the Technical Test in Chapter 17

Refer to Tutorial 17 for the questions to this exam given by TMS to developer candidates.

A1.

-1 -1 -1 .

The = operator in Visual Basic is used for both assignment (such as "a is assigned…") and comparison (such as testing the assertion that b has the same value as c-note the disuse of "equivalent"). The value &HFFFF is synonymous with the value of True and -1, so testing to see if -1 is the same value as &HFFFF yields True, or -1. As an aside, try changing Integer to Long throughout the code; you might be surprised to see -1 -1 -1 output here, too. For yet another result, try changing &HFFFF to 65535 (and use Longs)! Finally, try using 65535 with Integer. You'll see it causes an overflow error. A modification to the question, then, is to pose it again using one of these alternative forms and to ask why the results differ.(The answers are exercises for the reader.)

A2.

Code fragment A: Print the contents of the fourth item in the list box lstResults in the Debug window.

Code fragment B: Iterate through every item within the list box lstResults.

Code fragment C: If a selection has not been made in the list box lstResults, then …

Code fragment D: For each item up to the selected item, copy the index of each item within the list box lstResults into its ItemData property.

A3.

Public Function sNumToBin(ByVal nDecimal As Integer) As String
      Dim sBin  As String
      Dim nloop As Integer
      For nloop = 0 To 15
          sBin = IIf(nDecimal And 2 ^ nloop, "1", "0") & sBin
      Next
      sNumToBin = sBin
  End Function

A4.

Public Function itoh(ByVal nByte As Byte) As String
      Const c As String = "0123456789ABCDEF"
      itoh = IIf(nByte <= 15, Mid$(c, nByte + 1, 1), "?")
      ' OR perhaps...
      itoh = IIf(nByte <= 15, Hex$(nByte), "?")
      ' OR perhaps...
      If nByte <= 15 Then
          itoh = Mid$(c, nByte + 1, 1)
      Else
          itoh = "?"
      End If
  End Function

Many answers are possible-some might even include the use of the Choose and Switch functions.

A5.

Option 1: Insert the following code into the Form_Load procedure.

Me.Move (Screen.Width - Me.Width) \ 2, _
          (Screen.Height - Me.Height) \ 2

Option 2: Set the form's StartUpPosition property to CenterScreen at design time.

Screen resolution should not matter. Notice the use of the Integer division operator above; this might show you that someone is conscious of the language (knows about this operator) and is aware that clock cycles are more efficient.

A6.

Identifier Type Scope Answer
BM010 Form Form frm
FileOpen Menu - mnu
RecordCount Integer Global gn
FirstName String Array Modular mas
VehclNum Long Local l
Vehicles Combo Box - cbo
Time Label - lbl

Any "sane" prefix is fine, of course.

A7.

  1. The code fragment has a Function SomeFunc and a Sub SomeSub, both the Sub and the Function have ByRef arguments, and neither return a value. The code cmdTest_Click calls both routines. When SomeSub is called, a copy of the argument is passed overriding the effect of the implicit ByRef in the Sub declaration. When SomeFunc is called the argument is passed ByRef as declared. The output to the debug window will be 1 and 2.
  2. Both arguments get passed ByVal (to a copy of the actual argument), no errors occur, and the output to the debug window will be 1 and 1.
  3. The actual argument now gets passed ByRef; the output to the debug window will be 2 and 2.
  4. Yes, as in Part 2, the output to the debug window will be 1 and 1 because only a copy is passed.
  5. Pass by reference is faster.

As an aside, if SomeSub passes ByRef (as shown in the question), SomeSub (x) succeeds, forcing the "evaluation of x" to be passed rather than x itself-in other words, forces a ByVal result. (The "evaluation of x," called an anonymous object, is a value [the result] stored in a memory location other than that occupied by x.) However, calling SomeSub as SomeSub ByVal x doesn't work. It might be worth posing this variant of the question and asking what the difference is. (The answer is an exercise for the reader.)

A8.

Private Sub Form_Load()
      Dim nLoop  As Integer
      Const COLS As Integer = 3
      Const ROWS As Integer = 4
      Me.Caption = "Calculator"
      labDisplay.Caption = ""
      With cmdDigit(nLoop)
          ' Size form, label, and initial cmdDigit to look right.
          Me.Height = ROWS * .Height + labDisplay.Height + Me.Height - Me.ScaleHeight
          Me.Width = COLS * .Width + Me.Width - Me.ScaleWidth
          labDisplay.Move 0, 0, Me.Width - (Me.Width - Me.ScaleWidth), labDisplay.Height
          .Move 0, Me.ScaleHeight - .Height
      End With
      For nLoop = 1 To ROWS * COLS - 3
          Load cmdDigit(nLoop)
          With cmdDigit(nLoop)
              .Move cmdDigit(nLoop - 1).Left + .Width, _
                    cmdDigit(nLoop - 1).Top
              If 0 = nLoop Mod COLS Then
                  .Top = .Top - .Height
                  .Left = cmdDigit(0).Left
              End If
              ' Only want 10 numeric buttons so make 'extra'
              ' buttons non-functional.
              .Caption = IIf(nLoop <= 9, CStr(nLoop), "")
              .Visible = True
          End With
      Next
  End Sub
  Private Sub cmdDigit_Click(Index As Integer)
      labDisplay.Caption = labDisplay.Caption & cmdDigit(Index).Caption
  End Sub

A9.

This list isn't complete. Also, some assume that we're using the Option Compare Text statement.

InStr(1, "TMS", sSource, 1)
  InStr(Ucase$("TMS"), Ucase$(sSource))
  sSource = "TMS"
  StrComp(sSource, "TMS")

A10.

Function NTrim$(ByVal sString As String)
      Dim nPos As Integer
      nPos = InStr(1, sString, vbNullChar)
      Do While nPos <> 0
          sString = Left$(sString, nPos - 1) & _
                    Mid$(sString, nPos + 1)
          nPos = InStr(1, sString, vbNullChar)
      Loop
      NTrim$ = sString
  End Function

Or:

Function NTrim$(ByVal sString As String)
      Dim nPos As Integer
      nPos = InStrRev(sString, vbNullChar)
      Do While nPos <> 0
          sString = Left$(sString, nPos - 1) & _
                    Mid$(sString, nPos + 1)
          nPos = InStrRev(sString, vbNullChar)
      Loop
      NTrim$ = sString
  End Function

A11.

Function bFileExists(ByVal sFile As String) As Boolean
      On Error Resume Next
      Call GetAttr(sFile)
      bFileExists = True = (0 = Err.Number)
  End Function

This is another question for which there are many possible answers. Whichever answer is given, ensure that hidden files, system files, and folder files (directories) are detected-you're looking for the "been there, done that" answer. For example, the normal bFileExists = "" <> Dir$(sFile) (used as shown) won't work for such files; a developer who doesn't realize this might cause crucial code to fail, such as the following:

Sub MakeFolder(ByVal s As String)
      If Not bFileExists(s) Then MkDir (s)
  End Sub

A12.

Property procedures actually protect the property by only allowing (or disallowing) access to it through these procedures (Get/Let and Set); they are therefore safer. Property procedures can be used to filter invalid property assignments and give the programmer the option to validate assignment values before actually applying them. A Public variable (an item of data declared Public in a class) can be arbitrarily accessed and changed. (Many programmers, usually the less experienced ones, don't actually know how to use Property Set. This question might enlighten you as to who does and who doesn't.)

A class can only make data or functional properties (either explicitly or through property procedures) and methods visible outside of itself.

A13.

Code fragment A: Form Initialize only. No form instance is created. The application terminates immediately.

Code fragment B: Form Initialize only. No form instance is created. The application terminates immediately.

Code fragment C: Form Initialize and Load. There will be one (invisible) instance of Form1 once this code has executed. The application doesn't terminate.

A14.

The code is legal. The output to the Debug Window is as follows:

30
  10
  30
  20

A15.

Optional Arguments: Look out for the use of Variant as parameter type and the use of the IsMissing function to test for presence of optional parameter.

Call MsgBox( _
               sRequired _
             , vbOKOnly _
             , IIf( _
                    IsMissing(sDiscretionary) _
                  , App.EXEName _
                  , sDiscretionary _
                  ) _
             )

Parameter Arrays: Look for the final parameter to be declared as ParamArray.

Private Sub ParamTest(ByVal sMsg As String, ParamArray nArray())
      Dim nLoop As Integer
      For nLoop = Lbound(nArray) To Ubound(nArray)
          Debug.Print sMsg & CStr(nArray(nLoop))
      Next nLoop
  End Sub

Collections: Look for the creation of a collection object as a "New Collection," then look for classes to be added to the collection object using the Add method. Then look for the For Each operation to iterate through the members of the collection. (An answer in which dictionaries are mentioned demonstrates knowledge in Visual Basic 6.)

Dim cColl As New Collection
  cColl.Add item := Class1, key := 12
  For Each Class1 In cColl
      .
      .
      .
  Next cColl

A16.

VBCP was the Visual Basic Code Profiler add-in. It was used to ascertain the execution time of code and to find performance bottlenecks.

A17.

This code outputs Class1 onto the form.

A18.

n = ((((True And (&HFF + True)) And _
      ((&HFF00 + (Not Not True)) = Not False)) Or _
      (&HFF + (Not True))) Or &HFF00)
  -1

You're looking for any mention that an expression like (assuming n is 32) n = Not n = 32 (where n is now 0, or False if used in a Boolean expression) is very different from n = Not n (where n is now -33, or True if used in a Boolean expression).

A19.

Wherever code needs to branch, unconditionally, to a new location within a procedure. An answer along the lines of "I'd never use it because it's bad practice" (does this imply the candidate doesn't use error handlers?) probably ought to be discussed. For example, ask the candidate to explain why he or she wouldn't use it-perhaps you can also have the candidate compare GoTo with other unconditional jumps, such as Procedure Call, Exit, Exit Loop, Exit For, Exit Do, Exit Sub, and so on. Make a point of asking the candidate to explain the difference between If SomeCondition Then GoTo and If SomeCondition Exit Loop.