Turning API Errors into Basic Errors


One of the more common tasks for the hardcore API programmer is to turn an error returned from an API function call into a Visual Basic error. For example, here’s how you can call registry API functions (which always return 0 for success or an API error code):

ApiRaiseIf RegCloseKey(hKey)

If the return value from RegCloseKey (or any other registry API function) is 0, nothing happens. If it’s an error code, ApiRaiseIf creates a new Visual Basic error containing the official Windows error string for the associated error.


Sometimes with Windows functions, the return value indicates whether an error occurred but the code is returned through GetLastError (which Basic sees as Err.LastDllError) rather than through the error code. In that case, you raise the appropriate error with the ApiRaise procedure:

c = GetTempPath(cMaxPath, sRet)
If c = 0 Then ApiRaise Err.LastDllError

And if for some reason you just want to display the official error message ­without raising an error for it, you can call the ApiError function like this:

Debug.Print ApiError(Err.LastDllError)

How does this magic work? Well, Windows maintains all those error messages as resources in KERNEL32.DLL. These messages are localized: Bulgarian Windows has Bulgarian messages. You can get the error messages out of the DLL with the FormatMessage API function, using code like this:

Function ApiError(ByVal e As Long) As String
Dim s As String, c As Long
s = String(256, 0)
c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or _
FORMAT_MESSAGE_IGNORE_INSERTS, _
pNull, e, 0&, s, Len(s), ByVal pNull)
If c Then ApiError = Left$(s, c)
End Function

The FormatMessage function is overloaded to do many tasks. You pass constants in the first parameter to indicate which task you want. When retrieving error messages, most parameters are ignored. FormatMessage is an interesting function, but this is one of the few tasks it performs that makes sense in Visual Basic.

The Error Message program (ERRMSG.VBP) is the shortest use­-ful utility provided with this book. It puts a simple user interface around the message lookup code from ApiError. Just type in
an error number and it shows you the corresponding message.
I keep a copy of it on my desktop.


As you can imagine, the ApiRaise function just calls ApiError:

Sub ApiRaise(ByVal e As Long)
Err.Raise vbObjectError + 29000 + e, _
App.ExeName & “.Windows”, ApiError(e)
End Sub

Most common API errors fall in the range 1 through 999. I’ve randomly chosen 29000 as the base for API errors. So once again, let me raise a hopeless request that no one use error codes between 29001 and 29999 for anything other than creating fake API errors. I return the source as the project name combined with Windows. I’d prefer to give the specific system DLL that caused the error, but I couldn’t figure out any way to get that information.


The ApiRaiseIf procedure just uses the ApiRaise procedure to make the error- raising syntax a little cleaner:

Sub ApiRaiseIf(ByVal e As Long)
If e Then ApiRaise e
End Sub