RSS Feeds

Error Handling in VBScript - Part II

Interpreting the Error Code and Description

Let’s look in a bit more detail at how the interpreter within the VBscript engine handles errors and how they are recorded in Err. Errors can be raised by the interpreter itself (and examples of these are the Subscript out of range and Division by zero errors above), but the main power of scripting is its use as an integration vehicle for COM components such as ASDI, and many of the errors that need to be handled will originate in such components. When an error occurs the interpreter is going to get an HRESULT, and possibly some additional context information — strings describing the error, and so on, and as it uses the standard programmatic interface to COM by calling IDispatch and therefore errors are returned in an EXCEPINFO structure. (This design dates back to the earliest days of COM; sorry.)

Making sense of those error numbers requires some delving into the depths of how COM represents errors — the HRESULT, which is a 32 bit unsigned integer where the high bit indicates whether it is an error or a success. The remaining bits in the high word indicate the "facility" of the error -- into what broad category does this error fall? The low word indicates the specific error for that facility. HRESULTS are therefore usually talked about in hex, as the bit structure is a lot easier to read in hex! Consider 0x80070013, for example. The high bit is set, so this is an error. The facility code is 7 and the error code is 0x0013 = 19 in decimal. Some common facility codes are listed in Table 1 and Table 2 below.

Once the error winds its way back to the interpreter, the interpreter does a long jump to an error handling routine which saves off additional information that the interpreter knows. For instance, what is the name of the last-accessed variable -- because some error messages include information like that. The interpreter then checks to see if we're in 'resume next' mode, in which case it cleans up the stack, moves the instruction pointer to the next beginning-of-statement marker, and restarts the interpreter.

There is some additional goo that happens in here to make script debugging scenarios work. I won't go into that — a discussion of all the ways that script errors and the debugger interact would be lengthy indeed. There is also code to handle weird scenarios — like, a JScript block with a try-catch calls a VBScript block which calls a JScript block, which throws an exception — but I won't go into these, nor the detailed error tracking you’d observe if you were debugging the COM object itself — say through the Visual Studio debugger.

The implementation of the Err object should now be transparent — it simply looks at the information which the engine recorded at the time of the error. The error number, description, and so on, are reported as they were reported to us by the object which failed, assuming that the object returned error status. However for some common errors, when VBScript gets the error numbers back from calls to IDispatch objects, it replaces them with the equivalent VBScript error number. I have never particularly liked this feature, but VB6 does it, so we're stuck with it for backwards compatibility reasons. This can be a little confusing if you're debugging a problem -- you see one error go out of the object, but a different error is reported to the host. The mapping table that VBScript uses is below at Table 1. (Note that there seems little logical structure to these codes, so don’t look for one. They seem to have been assigned for largely historic reasons, to the extent that the error codes listed in blue are the same as Altair BASIC which Microsoft's first product, written by Bill Gates and Paul Allen back in 1975 for the Altair 8080!)

Table 1 — VBscript Errors Codes and Facility Mappings

No

Description

Facility Code

Facility Name

5

Invalid procedure call or argument

0x80070057

E_INVALIDARG

6

Overflow

0x8002000A

DISP_E_OVERFLOW

7

Out of memory

0x80030008

STG_E_INSUFFICIENTMEMORY

 

 

0x8007000E

E_OUTOFMEMORY

 

 

0x8002000B

DISP_E_BADINDEX

9

Subscript out of range

0x80028CA1

TYPE_E_OUTOFBOUNDS

10

This array is fixed or temporarily locked

0x8002000D

DISP_E_ARRAYISLOCKED

11

Division by zero

n/a

 

13

Type mismatch

0x80020005

DISP_E_TYPEMISMATCH

 

 

0x80028CA0

TYPE_E_TYPEMISMATCH

14

Out of string space

0x80029C4A

TYPE_E_CANTLOADLIBRARY

17

Can't perform requested operation

n/a

 

28

Out of stack space

n/a

 

35

Sub or Function not defined

n/a

 

48

Error in loading DLL

n/a

 

51

Internal error

n/a

 

52

Bad file name or number

n/a

 

53

File not found

n/a

 

54

Bad file mode

n/a

 

55

File already open

 

 

57

Device I/O error

0x80028CA2

TYPE_E_IOERROR

 

 

0x8003001D

STG_E_WRITEFAULT

 

 

0x8003001E

STG_E_READFAULT

 

 

0x80030103

STG_E_CANTSAVE

58

File already exists

0x80030050

STG_E_FILEALREADYEXISTS

61

Disk full

0x80030070

STG_E_MEDIUMFULL

62

Input past end of file

n/a

 

67

Too many files

0x80030004

STG_E_TOOMANYOPENFILES

 

 

0x80030012

STG_E_NOMOREFILES

68

Device unavailable

n/a

 

70

Permission denied

0x80030005

STG_E_ACCESSDENIED

 

 

0x80030013

STG_E_DISKISWRITEPROTECTED

 

 

0x80030021

STG_E_LOCKVIOLATION

 

 

0x80030100

STG_E_INUSE

 

 

0x80030101

STG_E_NOTCURRENT

 

 

0x80070005

E_ACCESSDENIED

71

Disk not ready

n/a

 

74

Can't rename with different drive

n/a

 

75

Path/File access error

0x80030020

STG_E_SHAREVIOLATION

76

Path not found

0x80030003

STG_E_PATHNOTFOUND

91

Object variable not set

n/a

 

92

For loop not initialized

n/a

 

94

Invalid use of Null

n/a

 

322

Can't create necessary temporary file

0x80028CA3

TYPE_E_CANTCREATETMPFILE

424

Object required

0x80040154

REGDB_E_CLASSNOTREG

429

ActiveX component can't create object

0x800401E3

MK_E_UNAVAILABLE

 

 

0x800401F3

CO_E_CLASSSTRING

 

 

0x800401F5

CO_E_APPNOTFOUND

 

 

0x800401FE

CO_E_APPDIDNTREG

 

 

0x80080005

CO_E_SERVER_EXEC_FAILURE

430

Class doesn't support Automation

0x80004002

E_NOINTERFACE

432

File name or class name not found during Automation operation

0x80030002

STG_E_FILENOTFOUND

 

 

0x800300FC

STG_E_INVALIDNAME

 

 

0x800401E6

MK_E_INVALIDEXTENSION

 

 

0x800401EA

MK_E_CANTOPENFILE

438

Object doesn't support this property or method

0x80020001

DISP_E_UNKNOWNINTERFACE

 

 

0x80020003

DISP_E_MEMBERNOTFOUND

 

 

0x80020006

DISP_E_UNKNOWNNAME

440

Automation error

0x80004001

E_NOTIMPL

445

Object doesn't support this action

n/a

 

446

Object doesn't support named arguments

0x80020007

DISP_E_NONAMEDARGS

447

Object doesn't support current locale setting

0x8002000C

DISP_E_UNKNOWNLCID

448

Named argument not found

0x80020004

DISP_E_PARAMNOTFOUND

449

Argument not optional

0x8002000F

DISP_E_PARAMNOTOPTIONAL

450

Wrong number of arguments or invalid property assigned

0x8002000E

DISP_E_BADPARAMCOUNT

451

Object not a collection

0x80020011

DISP_E_NOTACOLLECTION

453

Specified DLL function not found

0x8002802F

TYPE_E_DLLFUNCTIONNOTFOUND

455

Code resource lock error

n/a

 

457

This key is already associated with an element of this collection

n/a

 

458

Variable uses an Automation type not supported in VBScript

0x80020008

DISP_E_BADVARTYPE

462

The remote server machine does not exist or is unavailable

0x800706BA

RPC_S_SERVICE_UNAVAILABLE

481

Invalid picture

n/a

 

500

Variable is undefined

n/a

 

501

Illegal assignment

n/a

 

502

Object not safe for scripting

n/a

 

503

Object not safe for initializing

n/a

 

504

Object not safe for creating

n/a

 

505

Invalid or unqualified reference

n/a

 

506

Class not defined

n/a

 

507

An exception occurred

n/a

 

32811

Element not found

n/a

 

32812

The specified date is not available in the current locale's calendar

n/a

 



Table 2 — Standard Facility Codes

Symbolic Facility Code

Value

FACILITY_NULL

0

FACILITY_RPC

1

FACILITY_DISPATCH

2

FACILITY_STORAGE

3

FACILITY_ITF

4

FACILITY_WIN32

7

FACILITY_WINDOWS

8

FACILITY_SECURITY

9

FACILITY_CONTROL

10

FACILITY_CERT

11

FACILITY_INTERNET

12

FACILITY_MEDIASERVER

13

FACILITY_MSMQ

14

FACILITY_SETUPAPI

15

FACILITY_SCARD

16

FACILITY_COMPLUS

17

FACILITY_AAF

18

FACILITY_URT

19

FACILITY_ACS

20

FACILITY_DPLAY

21

FACILITY_UMI

22

FACILITY_SXS

23

FACILITY_WINDOWS_CE

24

FACILITY_HTTP

25

FACILITY_BACKGROUNDCOPY

32

FACILITY_CONFIGURATION

33

FACILITY_STATE_MANAGEMENT

34

FACILITY_METADIRECTORY

35

 

Table 3 — Some Other Common Errors

Facility Code

Facility Name

Description

0x8000FFFF

E_UNEXPECTED

"Catastrophic failure" — something completely unexpected has happened.

0x80004001

E_NOTIMPL

"Not implemented" — the developer never got around to writing the method you just called!

0x8007000E

E_OUTOFMEMORY

Pretty obvious what happened here

0x80070057

E_INVALIDARG

You passed a bad argument to a method

0x80004002

E_NOINTERFACE

COM is asking an object for an interface. This can happen if you try to script an object that doesn't support IDispatch.

0x80004004

E_ABORT

Whatever you were doing was terminated

0x80004005

E_FAIL

Something failed and we don't know what.

0x86664004

SCRIPT_E_RECORDED





 

This is how we internally track whether the details of an error have been recorded in the error object or not. We need a way to say "yes, there was an error, but do not attempt to record information about it again."

0x80020102

SCRIPT_E_PROPAGATE

Another internal code that we use to track the case where a recorded error is being propagated up the call stack to a waiting catch handler.

0x80020101

SCRIPT_E_REPORTED

The script engines return this to the host when there has been an unhandled error that the host has already been informed about via OnScriptError.

This is only a subset of the errors that can be detected. Also many COM objects are designed to provide a scripting-friendly interface and therefore include call-back methods to allow the script to interrogate any errors raised in the COM object. For example in WMI:

   On Error Resume Next
   Set Test = GetObject _
              ("Winmgmts:root\cimv2:Win32_Printer.Name='TestPrinter'")
   Set WMI_Error = CreateObject("WbemScripting.SwbemLastEror")
   Wscript.Echo WMI_Error.Operation & VbTab & _
   WMI_Error.ParameterInfo & VbTab & WMI_Error.ProviderName
    

However, for the reasons I discuss in the next section, you should only need to exploit this richness in very limited circumstances.

Comments

  • 1.
  • At Thu 27th December 2007, 12:20 pm,
  • Pallavi wrote:
Hello, error 438 MEMBERNOTFOUND - Could you plz tell how t sort out that for the following code. Error is coming in Visual Basic 2005 (i.e. VB .NET) for the fourth statement(ObjWb = AppXls.Workbooks.Add) in the following code. I searched ,but couldn't get relevent solution.
Imports Excel

Dim AppXls As Excel.Application Dim ObjWb As Excel.Workbook
AppXls = CreateObject("Excel.Application") ObjWb = AppXls.Workbooks.Add ObjWb.Worksheets().Items("Sheet1").range("A1").value = "1"
ObjWb.SaveAs("C\pp\test.xls") ObjWb.Close() AppXls.Quit()
added microsoft excel library, microsoft office lib. added namespace Excel i.e. Imports Excel. But still not sorting out. Could anybody plz help me? Would be appriciable. Thanks and regards.