Parsing Error Codes

Translate common Windows system and network error messages with ease

Bill Stewart

July 23, 2008

9 Min Read
ITPro Today logo in a gray background | ITPro Today



Error messages are common occurrences, and script and program authors try to make them as informative as possible. However, unexpected errors sometimes force the script or program to simply display a numeric error code. Whether the error condition is a result of poor programming or an unexpected condition (e.g., a network outage), it's sometimes important to have the description for an error code. This task isn't always completely straightforward—the code can be displayed as decimal, hexadecimal, or even a negative number. To make it easier to retrieve error-code descriptions, I wrote ErrorParser.hta, an HTML Application (HTA) that lets you enter a numeric code and click a button to get the Windows description of the error.

Understanding Windows API Error Codes

Before I describe how ErrorParser.hta works, I need to provide a bit of background about error codes. As you might know, the Windows API has a large list of standard error codes. These codes are returned as 32-bit unsigned integers. Signed integers can store negative values, but unsigned integers can't. The range of values for 32-bit signed integers is -2,147,483,648 to 2,147,483,647; the range of values for unsigned 32-bit integers is 0 to 4,294,967,295. The difference between the two types of values is how the bits for the number are stored in memory: A signed integer uses one of the bits to indicate whether the number is positive or negative.

This difference is sometimes important when interpreting an error code. A script or program reporting an error might interpret the OS’s error code (an unsigned integer) as a signed integer and display a negative value. For example, consider the GenerateError.js script in Listing 1. GenerateError.js (written in JScript) attempts to use the FileSystemObject object's GetFile method to retrieve a file object for a nonexistent file. When you run this script, it will echo a signed integer (-2,146,828,235) because Windows Script Host (WSH) incorrectly interprets the error code as signed. To convert a signed negative integer to its unsigned equivalent, we can use formula (232 - 1) - (~ n). In this formula, n is the signed value and the tilde character (~) is the bitwise NOT operator (VBScript uses the word Not). Using this formula, the signed equivalent of -2,146,828,235 is 2,148,139,061 (800A0035 in hex form).

However, if you peruse the list of Windows error codes at MSDN, you won't find 2,148,139,061 or 800A0035. The reason is that sometimes a program or a component will return an error in two parts. The rightmost 16 bits of the error value (the low word) contains the Windows error code; the leftmost 16 bits (the high word) are commonly used to indicate the component generating the error. In this case, 800A refers to a COM error and 35 hex, or decimal 53, is the Windows error code. In other words, code 800A0035 means "a COM automation object returned error 53."

Although this error message is informative, it would be also helpful if we could get only the Windows error code part (i.e., the low word). To obtain the low word, use the formula n << 16 >> 16. In this formula, the double left angle brackets (<<) are the bitwise left shift operator, and the double right angle brackets (>>) are the bitwise right shift operator. (VBScript doesn't have built-in bit-shifting operators, but JScript does.) If we apply this formula to the value 800A0035, we’re left with hex 35 (decimal 53). If you use the same formula on an error value that doesn't have a high word (i.e., the high word is all zeros), the formula returns the error value unchanged, so we can use this formula to get the Windows error code whether or not the error value has a high word.

An easy way to understand how this works is to use the built-in Windows calculator program. Once you've opened the calculator, from the View drop-down menu, select Scientific, then select the Hex and Dword buttons. Enter the error value 800A0035. We want to shift this value left by 16 bits to drop the 800A part of the number, so click the Lsh (left shift) button, enter the number 10 (16 in decimal), then click the equal (=) button. This operation shifts the number to the left 16 bits, leaving zeros for the rightmost 16 bits and the value 35 (53 in decimal) in the leftmost 16 bits. To drop the zeros, we want to shift the value right 16 bits, so select the Inv (inverse) check box, click Lsh, enter the number 10 (for 16 decimal), then click = again, leaving only the value 35.

Once you have the decimal value of the error code, you can run the Net helpmsg command to get the error's description. For example, the command

Net helpmsg 53

displays the description The network path was not found

ErrorParser.hta Overview

To use ErrorParser.hta to convert a numeric error code to its Windows equivalent, you simply enter an error code in the text box on the screen that Figure 1 shows and click Parse. The program will display the corresponding Windows error and description, if available, for the specified error.

The HTML portion of the application is straightforward: An tag provides a place to enter or paste the error code, and the Parse button is an input type="submit" tag that executes a JScript function to update the form. Four read-only tags display the decimal and hex equivalents of the error code, and a read-only tag displays the error description. The Help, Reset and Close buttons are the last three <input> tags on the form. The HTML code uses tables and Cascading Style Sheets styles to improve the form's visual appearance. </p><p>To use ErrorParser, double-click ErrorParser.hta in Windows Explorer or type the program name at a command prompt. Enter an error code and click the Parse button or press Enter. If the code is in hex form, prefix the number with 0x (e.g., 0x52E). Make sure that the number doesn't have a leading zero (unless you’re specifying 0x for a hex value); otherwise the application will interpret the code as an octal (base 8) value. To quickly enter a new value, press Enter or the spacebar to press the Reset button, which empties the form and places the cursor's focus back to the Error code field. </p><strong>The parseError Function</strong> <p>When you enter a value into the input field and click the Parse button, ErrorParser.hta executes the parseError function that Listing 2 shows. The parseError function first determines whether the error code is a nonempty string. Next, it uses JScript's parseInt function to convert the error code to a number, and it uses the isNaN function to determine whether the parseInt operation returned a number or JScript's special not-a-number value. JScript uses a special not-a-number value when an operation returns a value that isn’t a number, and the isNaN function tests whether an operation returned this value. For example, if you enter a non-numeric string in the error code field, the parseError function will fail to convert the string to a number, returning the not-a-number value. This is a simple way for the parseError function to perform input validation. </p><p>After this, the parseError function uses the toUnsigned function in Listing 3 to convert the numeric value to its unsigned equivalent if the value is less than zero. Unsigned 32-bit integers can't be larger than 4,294,967,295 (FFFFFFFF in hex), so the parseError function will alert the user if the error value is too large. The function then updates the first two read-only <input> tags on the form with decimal and hex equivalents of the full error code. Next, the parseError function uses this lo function </p><p style="font-size: 12px; font-family: Courier New">function lo(n) {<br> return n << 16 >> 16;<br>}</p><p>to retrieve the low-order 16 bits of the error code and updates the last two read-only <input> tags on the form with the decimal and hex equivalents of the Windows error code. </p><p>Finally, the parseError function calls the getErrorDescription function in Listing 4 to retrieve the error description for the decimal value of the Windows error code, and it updates the form's <textarea> object with the results from the getErrorDescription function. The parseError function then sets the focus to the Reset button on the form. </p><p><strong>The getErrorDescription Function </strong></p><p>The getErrorDescription function uses the Net helpmsg command to get the error description, if it's available, from the OS. First, the getErrorDescription function uses the FileSystemObject's GetTempName, GetSpecialFolder, and BuildPath methods in a do ... while loop to create a temporary filename in the temporary directory, as callout A in Listing 4 shows. This loop repeats while the file exists to ensure that the filename is unique. Next, the function constructs a command line like the following: </p><p style="font-size: 12px; font-family: Courier New">%SystemRoot%system32cmd.exe /c %SystemRoot%system32et.exe helpmsg errorcode > temporaryfile</p><p>The getErrorDescription function uses cmd.exe to run net.exe because output redirection (the > symbol) is a cmd.exe feature. Next, the function uses the WshShell object's Run method to execute the command line and wait until it's finished. When the command finishes executing, the temporary file will contain the output from the Net helpmsg command. </p><p>Next, the getErrorDescription function uses a try block to open the temporary file as a TextStream object using the FileSystemObject's OpenTextFile method. If the OpenTextFile method succeeds, the function uses the TextStream object's ReadAll method to read the entire contents of the file as a single string, removing leading and trailing white spaces in the process by using the trim function, as follows: </p><p style="font-size: 12px; font-family: Courier New">function trim(s) {<br> return s.replace(/(^s*)|(s*$)/g, "");<br>} </p><p>The trim function is not equivalent to VBScript's Trim function because it uses a regular expression that also removes blank lines at the beginning and the end of the string. The getErrorDescription function’s catch block executes in case either the OpenTextFile or the ReadAll methods fail. The finally block executes regardless of whether an error occurred; it closes the TextStream object and deletes the temporary file. </p><p>At this point in the getErrorDescription function, the result variable will contain a string. If the string is empty, the function replaces the string with a message indicating that it couldn't find the description for that error message. Otherwise, it returns the string. </p><p><strong>Know the Limitations </strong></p><p>ErrorParser.hta uses the Net helpmsg command to retrieve error descriptions, so it's subject to the Net helpmsg command's limitations. The Net helpmsg command retrieves descriptions for system and network error-code values only; other kinds of error codes (e.g., error codes from Active Directory or the DNS service) won't return a description. In those cases, you’ll need to refer to MSDN to find the error-code descriptions. Nevertheless, you should be able to find plenty of opportunities to use ErrorParser.hta. </p>

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like