Monday, 1 October 2012


What is an API?
API (Application Program Interface) is a function in DLL (Dynamic link library). Windows operating system is based on a couple of DLLs, such as Kernel32, User32, and GDI32. These APIs form the core part of Windows operating system. A DLL is a collection of functions (APIs). DLL is loaded into memory when any of the function is referred by an application. And once  a DLL is loaded in to memory DLL remains in memory and functions in DLL are dynamically bound to applications.  That means when an application calls a function in a DLL, the code of the function is not inserted into application (if it is done, it is called as static linking) and instead at run time the code of function is made available to application from DLL.

Dynamic linking is especially very efficient in Windows operating system, as a collection of application can run at the same time and may also use the same set of functions. So instead of placing one copy of each function in each application, it is better to provide one copy of functions and let all applications dynamically bind to functions.

Why to call APIs from Visual Basic?
Well, APIs are functions in DLLs and these APIs are what applications use indirectly or directly to get the job done in Windows OS. For instance, to show a window (a form in Visual Basic), to resize a window or to add an item to list box Windows use APIs.  All that is fine. But why should a Visual Basic programmer worry about all this? Because you say, I add an item using AddItem method of List box and show a form using Show method and so on. Accepted. But that is not the entire programming.

There are tasks (as you will see later) that you cannot accomplish just with commands of Visual Basic. You need to go beyond Visual Basic and access these APIs to get the job done. As you can see in figure 15.1, in most of the cases a command in Visual Basic ends up calling one of the APIs. But in some cases you do not find any command in Visual Basic that does the job for you. In this case you need to call APIs for VB application.
 

Figure 14.1: Calling API from Visual Basic application.


However, to call an API you need to know everything about API. First of all you should know whether there is any API that does the job that Visual Basic cannot do for you.  Then you must know the number of parameters, type of each parameter and the type of return value.  The following are the details you should have before you call an API.

¨         The name of API
¨         Details of Parameters such as number of parameters and type of each parameter
¨         The library (DLL) in which API is available
¨         What type of value the API returns?

How to call an API from Visual Basic?
In order to call an API from VB, you have to take two steps, they are :

¨         Declaring API using Declare Function or Declare Sub statement.
¨         Calling API just like how you call a Visual Basic function or procedure.
Declaring an API
The first thing that you have to do to call an API is declare it in your project. This is generally done in code module. However, it can be done in General/Declarations of any module.

Here is the complete syntax of Declare statement.

Declare {Function|Sub}  FunctionName  Lib  LibraryName” [Alias  
        Aliasname”]   (Argument list)  [As Returntype]

The following sections will explain how to use each part of the syntax.

Function or Sub

Specifies whether API returns a value or not. If API returns a value then it is to be declared as a Function otherwise as a Subroutine. (Sub)

FunctionName

This is the name that you want to use to call API in your program. This name may be different from the actual name of the API. In this case, you also have to specify Alias and give actual name as the alias.

Lib “LibraryName”

Specifies the name of the library (DLL) in which the declared API is existing.  This indicates to Visual Basic where to look for API. The library should be available for Visual Basic. If it is not a standard library such as Kernel32, User32 or GDI32 then it is better you specify the complete path.

Note: Suffix 32 for a library name denotes 32-bit library. If you are using 16-bit library, i.e. for windows 3.x then you just have to give Kernel and not Kernel32.

Alias “AliasName”

Specifies the actual name of API when FuctionName is different from actual name. This enables you to change the name of API in your program so that name is more easier to call or more meaningful.

Argument List

Specifies the list of arguments (also called as parameters). For each argument you have to specify how argument is passed – by value or by reference, the name of argument and type of argument.

An argument is passed either by value or by reference. When a value is passed by value, its value is passed to function and changes made to the argument that corresponds to the parameter will not effect the value passed. That means, for example,  if you pass variable X to a function by value then changes made by function  argument will not effect the value of variable X.  On the other hand, if an argument is passed by reference, the reference(address) of the variable is passed to function and as the result any changes made to argument in function will effect the value of variable that is passed to function.

Keyword ByVal is used to specify pass by value and ByRef is used to specify pass by reference.

Passing Strings

For strings, ByVal means convert a Visual Basic string to C string. It doesn’t mean that the string is passed by value. String is always passed by reference as its address is passed and not the value.

Also note, that when you pass a string, you have to create required amount of space in Visual Basic string before it is passed to an API. Because APIs use C string convention, which assumes that the string points the location that is allocated to it.

Here is an example:

 ‘ declare a string of 255 locations
 Dim st as string * 255
 ‘ call API and pass string to it
 V = APIFunction(st)


The above example can also be rewritten in this way:

‘ Declare a normal Visual Basic string
Dim st as string

St = space (255)    ‘ create space for 255 spaces
V = APIFunction (st)

Data Types used in API calls
When we deal with APIs we deal with C data types. So we have to convert Visual Basic data types to C data types.  The following table lists out the C data types and corresponding Visual Basic data types.

C Data Type
Size
Visual Basic Data Type
BOOL
32
Boolean
BYTE
8
Byte
Char
8
String * 1
Double
64
Double
DWORD
32
Long
Float
32
Single
HANDLE
32
Long
Int
32
Long
Long
32
Long
LPTSTR
32
No equivalent
LPCTSTR
32
No equivalent
Short
16
Integer
UINT
32
Long
ULONG
32
Long
USHORT
16
Integer
UCHAR
8
String * 1
WORD
16
Integer
Table 14.1: C data types and their equivalent data types in Visual Basic.


What is a Handle?
As long as you use Visual Basic command you live under cover. You do not know what is really happening outside Visual Basic. But the moment you decide to call an API, you need to understand what is happening under the hood. Handle is one of them. VB allows you to access object using object oriented syntax. But what’s really happening in Windows is concealed.

Every window is assigned and identified by a handle, which is a 32 bit number ( long integer). Windows OS identifies windows using handle. Remember each control, such as Text box, Command button, is also a window. These windows are called as control windows. So each control and form has a handle using which Windows OS identifies the controls and forms.

If you ever have to take the handle of a control or a form in Visual Basic, use hWnd property of the form or control. This property returns the handle of the form or control that is assigned by Windows OS.


Getting API declaration from WIN32API.TXT
When you want to get declarations of standard APIs, you can use WIN32API.TXT text file. It contains Visual Basic declarations for all standard APIs, constants, and Types.

Use program API Text View to load the text file and get required declarations. API Text Viewer is an Add-in. So it is to be first added to VBIDE.

You can run it using the following steps:

1.      Select Add-Ins menu and choose Add-In Manager option.
2.      Visual Basic displays Add-In Manager as shown in figure 14.2.
3.      Double click on VB 6 API Viewer to load it into VBIDE.
4.      Then click on Ok to close Add-In Manager window. This adds API Viewer to Add-Ins menu.
5.      Now again select Add-Ins menu and select API Viewer option.
6.      API Viewer starts. It doesn’t display anything initially. See figure 14.3.
7.      Select File-> Load Text File… option and select WIN32API.TXT file.
8.      API Viewer displays all the function declarations form WIN32API.TXT as shown in figure 14.2.
 
Figure 14.2: Loading Visual Basic 6 API Viewer.
 

Figure 14.3: API Viewer displaying WIN32API.TXT.

Sample Application
We will develop an application to display information regarding the following in different tabs.

¨         Windows Operating system
¨         Processor and Memory
¨         Selected Disk

Each tab displays information regarding one of the above mentioned topics. We will use TabStrip control to displays multiple tabs.

What is TabStrip Control?
TabStrip control is used to display multiple pages of information in one page by displaying one page at a time. Each page is called as a tab. Each tab is like a mini-form. Each tab contains a title. When user clicks on the title of the tab, the page that corresponds to the tab will be displayed.

To load TabStrip control into project:

1.      Select Project -> Components
2.      In Components dialog box, check Microsoft Windows Common Controls 6.0.
3.      Click on OK.

When a TabStrip control is placed on the form, it has only one tab. You need to create additional tabs, if you want, using the following procedure.

To create tabs in TabStrip control:

1.      Invoke property pages of TabStrip control by selecting Properties option in Context menu.
2.      Select Tabs tab in Property Pages.
3.      Click on Insert Tab button to add a new tab. Repeat the process for each tab.
Note: TabStrip is not a container control. You have to use other containers such as Frame control to place controls on Tabs of TabStrip control.

We will understand more about TabStrip control, as we will proceed.

Designing User Interface
As I have already mentioned in this application user interface is consisting of TabStrip control with three different tabs. First we will create three tabs using the procedure explained above, and then change Caption property of first tab to  "Windows Information", second tab to "System Information" and third tab to "Disk Information".

See figure 14.4, 14.5 and 14.6 to know how these three tabs appear at runtime, what is the information displayed in each of these tabs and how controls are arranged.
 

Figure 14.4:Windows Information Tab.
 

Figure 14.5: System Information Tab.

Figure 14.6: Disk Information tab displaying information regarding selected drive.

Follow the steps given below to create required controls:

Create a Frame and change the following properties

Name        Frames
Caption     "" (Null string)
Index       1

Index property is used to create a control array. Control array concept explained in chapter 8. A control array is a collection of controls that have the same name but different values for Index property. For all controls in a control array there is only one event procedure for each event.

Place second frame and change the following properties.

Name        Frames
Index       2
Caption     "" (Null string)

Place one more frame (third frame) and change the following properties.

Name        Frames
Index       3
Caption     "" (Null string)

Adding Control to Frames
After frames are added, place required controls on each frame. See figure 17.4, 17.5 and 17.6 for layout of the controls. Most of the controls are Labels. We set BorderStyle property to 1-Fixed Single for labels that display the values.

However, in third frame (Disk information), we have to place a DriveListbox control, which allows user to select the drive for which the user wants to get details.

Adding a module to contain API declarations
Generally we place all API declarations in a code module. Now we add a code module to the project using Project -> Add Module.

Add the Type declarations shown in table 14.2 using API Viewer.  

To get the Type declaration from API Viewer, do the following:

1.      Load Win32Api.txt using File-> Load Text File…
2.      Select Types in API Types dropdown list box.
3.      Select one type at a time and click on Add button to add the Type declaration to Selected Items.
4.      Repeat the process until all types listed in table 14.2 are added.

At the end of the above process all three Type declarations should be copied to General/Declarations of the code module, as shown in listing 14.1.

Here is the list of Types taken from API Viewer and what they contain.

Type

Meaning

MEMORYSTATUS
Contains fields that return the information regarding total physical memory, available memory etc.
SYSTEM_INFO
Contains fields that return information regarding number of processors, type of processor etc.
OSVERSIONINFO
Contains fields that return information regarding platform id, major and minor version etc.
Table 14.2: Type declarations required for sample application.

Add API declarations for the APIs listed in table 14.3 using API Viewer.

To add API declarations, do the following:

1.      Select Declares in API Type dropdown list box.
2.      Select each function listed in table 14.3 and click on Add button to send its declaration to Selected Items.
To transfer selected items to code module in Visual Basic project:

1.      Once all Types and Declarations are copied to Selected Items, click on Copy button to copy selected items to clipboard.
2.      Then activate code module in Visual Basic project and select General/Declarations.
3.      Choose Edit->Paste in VB IDE to paste Type declarations and API declarations that are copied into clipboard, into code module.
Public Type MEMORYSTATUS
        dwLength As Long
        dwMemoryLoad As Long
        dwTotalPhys As Long
        dwAvailPhys As Long
        dwTotalPageFile As Long
        dwAvailPageFile As Long
        dwTotalVirtual As Long
        dwAvailVirtual As Long
End Type

Public Type SYSTEM_INFO
        dwOemID As Long
        dwPageSize As Long
        lpMinimumApplicationAddress As Long
        lpMaximumApplicationAddress As Long
        dwActiveProcessorMask As Long
        dwNumberOrfProcessors As Long
        dwProcessorType As Long
        dwAllocationGranularity As Long
        dwReserved As Long
End Type

Public Type OSVERSIONINFO
        dwOSVersionInfoSize As Long
        dwMajorVersion As Long
        dwMinorVersion As Long
        dwBuildNumber As Long
        dwPlatformId As Long
        szCSDVersion As String * 128 'Maintenance string for PSS usage
End Type

Public Declare Function GetWindowsDirectory Lib "kernel32" Alias   "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

Public Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Public Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)

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

Public Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Public Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" (ByVal lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As Long, lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As Long) As Long

Public Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long

Public Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" (ByVal lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal nFileSystemNameSize As Long) As Long

Public Declare Sub GlobalMemoryStatus Lib "kernel32" (lpBuffer As MEMORYSTATUS)

Public Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Listing 14.1: Type declarations and API declarations.
Here is the list of functions used in the sample application and what they do?

API
Meaning
GetWindowsDirectory
Returns the name of the directory into which Windows OS is installed.
GetTempPath
Returns path for temporary directory (temp).
GetSystemInfo
Returns information regarding system into a variable of SYSTEM_INFO type.
GetUserName
Returns the name of the current user.
GetComputerName
Returns the name of the computer.
GetDiskFreeSpace
Returns the space details of the given disk.
GetVersionEx
Returns details regarding windows version into a variable of type OSVERSIONINFO.
GetVolumeInformation
Returns the details of the specified volume.
GlobalMemoryStatus
Returns memory statistics into a variable of type MEMORYSTATUS.
GetDriveType
Returns the type of the specified drive.
Table 14.3: APIs used in the sample application.

Writing code to get required information
Write three user-defined functions, GetSystemInformation, GetDiskInformation, and GetWindowsInformation.  These user-defined functions call APIs and get the required information. These functions also populate corresponding labels with the required information. Listing 14.2 shows the code for these three user-defined functions.

Public Sub GetWindowsInformation()

Dim winfo   As OSVERSIONINFO
Dim wdir As String * 255
Dim wlen As Long
 ' get windows platform

 wlen = GetWindowsDirectory(wdir, 255)
 lblwindir.Caption = Left(wdir, wlen)
 wlen = GetTempPath(255, wdir)
 ' get
 lbltemppath.Caption = Left(wdir, wlen)
 winfo.dwOSVersionInfoSize = Len(winfo)
 wlen = GetVersionEx(winfo)

  With winfo
    If .dwPlatformId = 0 Then
          lblwinplatform.Caption = "Windows 3.X"
    ElseIf .dwPlatformId = 1 Then
          lblwinplatform.Caption = "Windows 95"
    ElseIf .dwPlatformId = 2 Then
          lblwinplatform.Caption = "Windows NT"
    Else
          lblwinplatform.Caption = "Unknown"
       
    End If
   
    lblversion.Caption = .dwMajorVersion & "." & .dwMinorVersion
  
 End With

End Sub

Public Sub GetSystemInformation()

Dim sinfo As SYSTEM_INFO
Dim minfo As MEMORYSTATUS
Dim slen  As Long
Dim cname As String * 100
Dim rcode As Long

  ' call API to get information
 
  GetSystemInfo sinfo
  With sinfo
     lblprocessor.Caption = .dwProcessorType
  End With
  ' get memory information
  minfo.dwLength = Len(minfo)
  GlobalMemoryStatus minfo
  With minfo
     lbltotalmemory.Caption = .dwTotalPhys
     lblfreememory.Caption = .dwAvailPhys
     lblutilization.Caption = .dwMemoryLoad
  End With
 
  ' get computer name
  slen = 100
  rcode = GetComputerName(cname, slen)
  lblcomputername.Caption = Left(cname, slen)
  ' get current user name
 
  slen = 100
  rcode = GetUserName(cname, slen)
  lblcuruser.Caption = Left(cname, slen)
 
 
End Sub

Private Sub Drive1_Change()
  GetDiskInformation Left(Drive1.drive, 1) & ":\"
End Sub

Private Sub Form_Load()
    
   x = TabStrip1.Left + 40
   Y = TabStrip1.Top + 300
   For i = 1 To 3
      frames(i).Visible = False
      frames(i).Move x, Y, TabStrip1.Width, TabStrip1.Height - 300
   Next
   frames(1).Visible = True

   ' get the information
   GetWindowsInformation
   GetSystemInformation
   ' get current drives information
   GetDiskInformation Left(CurDir, 3)
End Sub

Private Sub TabStrip1_Click()
   ' make all frames invisible
   For i = 1 To 3
     frames(i).Visible = False
   Next
   ' make the selected frame visible
   frames(TabStrip1.SelectedItem.Index).Visible = True
End Sub

Public Sub GetDiskInformation(drive As String)
Dim vname As String * 100
Dim vserial As Long
Dim mcl As Long
Dim vfsys As Long
Dim vfsysname As String * 100
Dim x As Long
Dim dtype As Long
Dim dt As String
  ' get volume information
   x = GetVolumeInformation(drive, vname, 100, vserial, mcl, _
                              vfsys, vfsysname, 100)
 
   lblvolume.Caption = vname
   lblserial.Caption = vserial
   lblFilesystem.Caption = vfsysname
  
   ' get disk information
  
   x = GetDiskFreeSpace(drive, nspc, bps, fc, tnc)
   lblsectors.Caption = nspc
   lblbytespersector.Caption = bps
   lblfreeclusters.Caption = fc
   lblclusters.Caption = tnc
   ' get drive type
   dtype = GetDriveType(drive)
  
   Select Case dtype
      Case 0
            dt = "Unknown"
      Case 1
            dt = "Not Available"
      Case 2
            dt = "Removable"
      Case 3
            dt = "Fixed"
      Case 4
            dt = "Remote"
      Case 5
           dt = "CDROM"
      Case 6
           dt = "RAM Disk"
   End Select
  
   lbldrivetype.Caption = dt
 End Sub
Listing 14.2: Code for Sample application.

When you run the project, you will see the first tab (Windows Information) as we have shown that in Load event of the form. Whenever user clicks on any other tab, Click event of TabStrip control occurs. We take Index of the selected item tab and use that index to display the frame that has the same index. See the code for Click event of TabStrip1 (see listing 14.1) for complete code.

Whenever user selects a different drive letter in DriveListBox of Disk Information tab, we invoke GetDiskInformation by sending the name of the selected drive.

The ability to call an API from Visual Basic application is a very important facility. In several cases you find that what you want, cannot be done in Visual Basic and you need to call an API. What we have seen in our sample application is a tiny list of APIs. There are thousands of APIs. Try to understand as many APIs as possible. Because, using APIs you can push limits.

Thursday, 27 September 2012

Runtime Error Handling


Errors that occur in your program are of three types. They are syntax errors, runtime errors and logical errors. Syntax errors are errors that occur because of improperly written statements. Main causes for syntax errors are incorrectly typed words, unmatched if statements etc. Among all, syntax errors are the easiest to detect and rectify. Logical errors are errors in the logic of the program. That means the entire program runs, but it doesn’t produce the results that are required.  Logical errors are very difficult to detect and remove. Sometimes days may be passed but the errors may not be detected. So logical errors could cause nightmares. The task of finding out the errors becomes difficult proportionate to the size of the program.

Runtime errors are the errors that occur during the execution of the program and cause program to be terminated abruptly. A few examples of runtime errors are Division by Zero, File not found and Disk not ready. A good program should not be terminated abruptly.  So we have to take control when a runtime error occurs and handle the errors (recover from the error).

How To Handle Runtime Errors
To handle runtime errors we have to use On Error statement. On Error statement sends control to the given label whenever a runtime error occurs in any of the statements given after On Error and before the end of the block (procedure or function).

The following are the various formats available for On Error statement.

On Error GoTo line
On Error Resume Next
On Error GoTo 0

We will discuss about last two syntaxes later. First let us concentrate on first syntax. Line is either the line number or a label that is given before the line. Whenever an error occurs in the code that is after On Error, control goes to the given label.

Let us assume we want to open a file. We take filename from user using an InputBox. If file is not opened Visual Basic, by default displays a runtime error and terminates the program. To prevent it now we want to handle runtime error that might occur during Open statement as follows:

Private Sub Command1_Click()

 On Error GoTo errlabel
 fn = InputBox("Enter filename")
 Open fn For Input As #1
 ' process the file

 Close #1
 Exit Sub

errlabel:
   MsgBox "File not found. Please try again"
End Sub
Listing 13.1: Handling error that might occur because of Open statement.

In the above code, if Open statement failed and resulted in a runtime error then that error is trapped by On Error statement and control is passed to errlabel label.  Then given message is displayed and control comes out of procedure. If error is not trapped then an error message is displayed by Visual Basic and program is terminated.

Exit Sub statement is used to come out of procedure without entering into error handler. If Exit Sub is not given, though file is successfully processed, control goes to msgbox statement and error message is displayed. To prevent control from moving to error handler, Exit Sub statement is used.

Err Object
Err object contains information about run-time error. The information is accessed using the properties of Err object.  Err object also has two methods. The following table provides information regarding each property and method.

Type
Name

Description

Property
Number
Contains the error code of the error that occurred most recently.

Description
Contains error message.

Source
Contains the name of the object or application that caused the error.

LastDLLError
Contains the most recent system error that occurred when you call a DLL.
Method
Clear
Clears all property setting of Err object

Raise
Raises an error. See section “User defined errors”.
Table 13.1: Properties and methods of Err object.                 

 

Err object could be used to get the exact reason for error and the source of error etc.  For an example of Err object please see  “Resume statement” later.


User Defined Errors
Whenever there is an error, Visual Basic raises runtime error. It is also possible to raise your own errors using Raise method of Err event.

The syntax of Raise method is:

Raise number, source, description, helpfile, helpcontext

Here is the meaning of each parameter.

Argument

Description

Number
Identifies the nature of the error. Visual Basic errors (both Visual Basic-defined and user-defined errors) are in the range 0–65535. The range 0–512 is reserved for system errors; the range 513–65535 is available for user-defined errors. When setting the Number property to your own error code in a class module, you add your error code number to the vbObjectError constant. For example, to generate the error number 513, assign vbObjectError + 513 to the Number property.
Source
Name of the object or application that generated the error. When setting this property for an object, use the format projectname.classname. If source is not specified, the programmatic ID of the current Visual Basic project is used.
Description
Describing the error. If unspecified, the value in Number is examined. If it can be mapped to a Visual Basic run-time error code, the string that would be returned by the Error function is used as Description. If there is no Visual Basic error corresponding to Number, the "Application-defined or object-defined error" message is used.
HelpFile
The fully qualified path to the Help file in which help on this error can be found. If unspecified, Visual Basic uses the fully qualified drive, path, and file name of the Visual Basic Help file.
HelpContext
The context ID identifying a topic within helpfile that provides help for the error. If omitted, the Visual Basic Help file context ID for the error corresponding to the Number property is used, if it exists.

To generate an error with error number 500, enter:

‘ clear all the properties before you raise error to clear values for ' all the properties
Err.clear
‘Raise error
 Err.raise  vbobjecterror + 500,, “Insufficient Balance”

 

Resume statement
Resume statement is used in error handler to resume execution after handling error. The following are the options available with Resume statement.

Resume
Resume Next
Resume line

Resume statement alone resumes execution with the statement that caused the error. For example open statement failed because of missing floppy in floppy drive. Then you can prompt user to insert floppy and reexecute the statement so that this time, the file is successfully opened.

Resume Next statement resumes execution with the next statement of the statement that caused error. For example, when a particular read statement could not read the data from a file, If you want to ignore that statement and proceed with remaining statements, use Resume Next.

Resume Label statement allows you to resume execution from the given label.  This label could be anywhere in the same procedure.

Private Sub Command1_Click()
 On Error GoTo errlabel
Retry:
 fn = InputBox("Enter filename")
 Open fn For Input As #1
 ' process the file

  Close #1
 Exit Sub
errlabel:
   Select Case Err.Number
    Case 71  ' disk not ready
       resp = MsgBox("Disk is not ready. Do you want to retry?", vbYesNo)
       If resp = vbYes Then
           Resume   ' execute OPEN statement
       End If
    Case 53   ' file not found
       resp = MsgBox("File not found. Do you want to reenter filename?", vbYesNo)
       If resp = vbYes Then
           Resume retry
      End If
   Case Else
          Msgbox  err.description
  End Select
End Sub
Listing 13.2: Error handling with resume statement.

In the above example, we have used Err object to find out the exact problem and we have taken appropriate action. We have checked for two specific events - Disk not ready and File not found. If Disk is not ready then we have prompted user to specify whether he would like to retry. If user wants to retry then he would make disk ready and click on Yes button. Then program resumes execution with Open statement as we have used Resume statement, which resumes execution with the statement that caused the error.

If error is ‘File not found” then we are giving user a chance to reenter the file name. We have used Resume statement with a label to resume execution from retry label.  Retry label is given before InputBox statement, as a result user is prompted to enter filename again.

On Error Resume
This is one of the formats available for On Error statement. This statement ignores errors and resumes execution as if no error has occurred. In this, programmer is responsible for finding out whether a statement is successful.  The following is an example where we check whether Open statement is successful.

Private Sub Command1_Click ()
  On Error Resume Next
  Open fn For Input As #1
  If Err.Number <> 0 Then
     ' display error message
     MsgBox Err.Description
     Exit Sub
  End If
End Sub
Listing 13.3: Code to ignore error and continue.
On Error GoTo 0
Error trapping is automatically disabled when the procedure finishes execution. However, you can also turn off error trapping using On Error GoTo 0 statement.  Once Visual Basic executes this statement, error trapping is disabled and default error handling will be enabled.