Click here to Skip to main content
6,636,867 members and growing! (20,762 online)
Email Password   helpLost your password?
Languages » VB.NET » HowTo     Intermediate License: The Code Project Open License (CPOL)

Raising API exceptions from Visual Basic .NET

By Duncan Edwards Jones

How to raise API exceptions from Visual basic .NET.
VB, Windows, .NET 1.0, Visual Studio, Dev
Posted:4 Mar 2003
Views:39,437
Bookmarked:13 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
5 votes for this article.
Popularity: 3.23 Rating: 4.63 out of 5

1

2
1 vote, 20.0%
3
1 vote, 20.0%
4
3 votes, 60.0%
5

Introduction

Although the .NET framework wraps up the majority of Windows API in an easy to use and safe framework, there are occasions when a direct call to the Windows API cannot be avoided. In such cases it is useful to be able to provide meaningful exceptions should any error occur in the API call.

Telling the system that you want to be able to get the last API error

When you declare an API function in VB.NET, you set the attribute SetsLastError to indicate that if an error occurs while calling that function it should set the last error for you. For example, the declaration of the API call MessageBeep would be declared as:

 <DllImport("user32", EntryPoint:="MessageBeep", _ 
  SetLastError:=True, _ 
  CallingConvention:=CallingConvention.StdCall)> _
   Public Shared Function MessageBeep _ 
          ByVal uType As Int32 ) As Boolean  
   End Function

According to the documentation for this function on MSDN this function returns non-zero on success and sets the last error on failure. The parameter uType only accepts certain values so passing an incorrect value will set this error value to 87 meaning that the parameter is incorrect.

Getting the last error value

In Visual Basic 5 or 6 the error used to be held in Err.LastDllError. In Visual Basic .NET this has been replaced by the GetLastWin32Error.

Imports System.Runtime.InteropServices 
'\\ Print last api error number

Debug.Write(Marshal.GetLastWin32Error)

Getting the text description of this error

The Windows API has a function, FormatMessage that can be used to turn the number of the last error to a meaningful description. This is declared as:

   <DllImport("kernel32.dll", EntryPoint:="FormatMessageA", _ 
   CharSet:=CharSet.Ansi, _ 
   ExactSpelling:=True, _ 
   CallingConvention:=CallingConvention.StdCall)> _ 
   Public Shared Function FormatMessage( _
      ByVal dwFlags As Format_Message_Flags, ByVal lpSource As Int32, _ 
      ByVal dwMessageId As Int32,  ByVal dwLanguageId As Int32,  _
      ByVal lpBuffer As StringBuilder, _ 
      ByVal nSize As Int32, ByVal Arguments As Int32) As Int32 
    End Function

and used as:

  Imports System.Text
  Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000 
   Private Const MAX_MESSAGE_LENGTH = 512 
    Private Function GetAPIErrorMessageDescription( _
                                 ByVal ApiErrNumber As Int32) As String 
         Dim sError As New StringBuilder(MAX_MESSAGE_LENGTH) 
         Dim lErrorMessageLength AsInt32 
         lErrorMessageLength = _
            FormatMessage(Format_Message_Flags.FORMAT_MESSAGE_FROM_SYSTEM,  _ 
                           0, ApiErrNumber, 0, sError, sError.Capacity, 0)     
         If lErrorMessageLength > 0 Then
            Return sError.ToString 
         End If
    End Function

Wrapping this up in a class derived from Exception

To be of use to the VB.NET Try..Catch..Finally syntax for error handling, this code must be wrapped up in a class that is derived from Exception.

 Public Class ApiException 
    Inherits ApplicationException

And the New constructor is overridden to put the last system error in place of the base class' Message member:

 Private msMessage As String
    Public Sub New()
      '\\ Get the error message from the last error from the windows API...

      msMessage = GetAPIErrorMessageDescription(Marshal.GetLastWin32Error) 
    End Sub
    Public Overrides ReadOnly Property Message() As String 
      Get 
         Return msMessage 
      End Get
    End Property

Using the ApiException class

You can now write wrappers for your API calls that raise ApiException. E.g.:

Public Sub ApiMessageBeep(ByVal uType As Int32) 
  If Not Messagebeep(uType) Then
     Throw New ApiException
  End If
End Sub

Acknowledgements

This article was originally published on the Merrion Computing website.

Appendix: Full class code

Imports System.Text
Imports System.Runtime.InteropServices
Public Class ApiException
    Inherits ApplicationException
#Region "API Declarations"
    <DllImport("kernel32.dll", EntryPoint:="FormatMessageA", _
 CharSet:=CharSet.Ansi, _
 ExactSpelling:=True, _
 CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function FormatMessage( _
                                  ByVal dwFlags As Format_Message_Flags, _
                                  ByVal lpSource As Int32, _
                                  ByVal dwMessageId As Int32, _
                                  ByVal dwLanguageId As Int32, _
                                  ByVal lpBuffer As StringBuilder, _
                                  ByVal nSize As Int32, _
                                  ByVal Arguments As Int32) As Int32
    End Function
#End Region
#Region "Private members"
    Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
    Private Const MAX_MESSAGE_LENGTH = 512
#End Region
#Region "Private member variables "
    Private msFunctionName As String
    Private msMessage As String
#End Region
    Private Function GetAPIErrorMessageDescription(_
                                       ByVal ApiErrNumber As Int32) As String

        Dim sError As New StringBuilder(MAX_MESSAGE_LENGTH)
        Dim lErrorMessageLength As Int32

        lErrorMessageLength = _
                 FormatMessage(Format_Message_Flags.FORMAT_MESSAGE_FROM_SYSTEM, 
                                0, ApiErrNumber, 0, sError, sError.Capacity, 0)
        If lErrorMessageLength > 0 Then
            Return sError.ToString
        End If
    End Function
    Public Sub New(ByVal ErrNumber As Int32, ByVal FunctionName As String)

        '\\ Get the error message from the windows API...

        msMessage = GetAPIErrorMessageDescription(ErrNumber)
        msFunctionName = FunctionName
    End Sub
    Public Sub New(ByVal ErrNumber As Int32)

        '\\ Get the error message from the windows API...

        msMessage = GetAPIErrorMessageDescription(ErrNumber)
    End Sub
    Public Sub New()
        '\\ Get the error message from the last error from the windows API...

        msMessage = GetAPIErrorMessageDescription(Marshal.GetLastWin32Error)
    End Sub
    Public Sub New(ByVal FunctionName As String)
        '\\ Get the error message from the last error from the windows API...

        msMessage = GetAPIErrorMessageDescription(Marshal.GetLastWin32Error)
        msFunctionName = FunctionName
    End Sub
    Public ReadOnly Property FunctionName() As String
        Get
            Return msFunctionName
        End Get
    End Property
    Public Overrides ReadOnly Property Message() As String
        Get
            Return msMessage
        End Get
    End Property
End Class

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Duncan Edwards Jones


Member
Microsoft MVP 2006, 2007
Visual Basic .NET
Occupation: Software Developer (Senior)
Location: Ireland Ireland

Other popular VB.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
GeneralA simpler solution PinmemberMaximilian Hänel4:39 6 Mar '03  
GeneralRe: A simpler solution PinmemberMaximilian Hänel4:46 6 Mar '03  
GeneralRe: A simpler solution PinmemberMerrion5:53 6 Mar '03  
GeneralRe: A simpler solution PinmemberMaximilian Hänel10:17 6 Mar '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 4 Mar 2003
Editor: Rinish Biju
Copyright 2003 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2009
Web19 | Advertise on the Code Project