CWinAPIException

Introduction

The MFC library provides a series of classes for handling exceptions. For example, CFileException can be used for handling exceptions thrown from CFile methods, CMemoryException can be used for handling out-of-memory exceptions thrown by the new operator, and so on.

Sometimes you need to extend MFC by writing your own classes with corresponding exception classes. As long as usually you are using Windows API calls (like MFC generally does), an exception class for handling Windows API errors would be great.

First, let's take a fast look into CException.

CException class

CException is the base class for all other MFC exception classes.
It has two virtual functions:

  • GetErrorMessage - gets a string which describes the error;
  • ReportError - displays a message box showing the error message.
If derive from CException, then you can override one or both of these virtual functions to provide your own error descriptions and message boxes. Now, we can go further and implement the exception class for generic WinAPI errors.

A lite CWinAPIException class

class CWinAPIException : public CException  
{ 
public:
   CWinAPIException(DWORD dwError) : m_dwErrorCode(dwError) {}
   
// Attributes
private:
   DWORD m_dwErrorCode;    // error code given by Windows API 
   
// Overrides
public:
   virtual BOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
      PUINT pnHelpContext = NULL);
   virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);
// ...
};
CWinAPIException overrides CException::GetErrorMessage and CException::ReportError (more info about implementation can be found in the attached sources). We could stop here, but no... CWinAPIException can do more.

An improved CWinAPIException class

Usually MFC exception classes only give the error description, as for example "Path not found". Sometimes is useful to have more information such as the exception source (source file name and code line number). CWinAPIException can provide this additional information at the programmer's request. Let's say, in a beta release of an application we can choose to get all the information, while later in a more stable version we can set to display only the error description. Here is the complete CWinAPIException class:

class CWinAPIException : public CException  
{
   DECLARE_DYNAMIC(CWinAPIException)
      
// Constructor
private:
   CWinAPIException(DWORD dwError, LPCTSTR pszFile, UINT nLine, COleDateTime& odtTime);

// Attributes
private:
   DWORD m_dwErrorCode;    // error code given by Windows API 
   CString m_strFile;      // the file from which the exception was thrown
   UINT m_nLine;           // the line from which the exception was thrown
   COleDateTime m_odtTime; // date/time when exception occurred
   
   // switches used for customizing displayed info 
   static bool m_bShowErrorCode, m_bShowTimestamp, m_bShowSource;
   
// Overrides
public:
   virtual BOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
      PUINT pnHelpContext = NULL);
   virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);
   
// Operations
public:
   // method for throwing exceptions
   // NOTE: Prefer below macros instead of directly CWinAPIException::Throw call!
   static void Throw(DWORD dwError, LPCTSTR pszFile, UINT nLine);
   // accessors for custom display switches
   static void ShowErrorCode(bool bShowErrorCode) {m_bShowErrorCode = bShowErrorCode;}
   static void ShowSource(bool bShowSource) {m_bShowSource = bShowSource;}
   static void ShowTimestamp(bool bShowTimestamp) {m_bShowTimestamp = bShowTimestamp;}
   static bool IsErrorCodeShown() {return m_bShowErrorCode;}
   static bool IsSourceShown() {return m_bShowSource;}
   static bool IsTimestampShown() {return m_bShowTimestamp;}
   
// Implementation
private:
   void FormatMessage(CString& strText, LPCTSTR pszSep);
   void FormatMessageFromSystem(CString& strMessage);
};

There remains just few little things to add. When throwing an exception by calling CWinAPIException::Throw you have to pass the error code dwError, the source (full path and) file name pszFile, and the code line number nLine. The error code is usually retrieved with ::GetLastError. For source file name and line number can be passed the predefined macros __FILE__ and __LINE__, respectively. To make this task easier I have added the following macros to be used instead of CWinAPIException::Throw:

#define WINAPI_THROW_ERROR(e)          CWinAPIException::Throw(e, __FILE__, __LINE__)
#define WINAPI_THROW_LAST_ERROR        WINAPI_THROW_ERROR(::GetLastError())

// use this macro for functions which return 0 (FALSE) in case of failure
#define WINAPI_VERIFY_TRUE(r)          if(!r) WINAPI_THROW_LAST_ERROR;
// use this macro for functions which returns NULL in case of failure 
#define WINAPI_VERIFY_NOT_NULL(r)      if(NULL == r) WINAPI_THROW_LAST_ERROR;
// use this macro which return ERROR_SUCCESS in case of success and an error code otherwise
#define WINAPI_VERIFY_ERROR_SUCCESS(r) if(ERROR_SUCCESS != r) WINAPI_THROW_ERROR(r);

Examples

  • Using WINAPI_VERIFY_TRUE to throw an exception in case of failure (the function returns FALSE)
       BOOL bRet = ::AppendMenu(hMenu, MF_STRING, nID, pszNewItem);
       WINAPI_VERIFY_TRUE(bRet);
    
  • Using WINAPI_VERIFY_NOT_NULL to throw an exception in case of failure (the function returns NULL)
       SC_HANDLE hSCManager = ::OpenSCManager(NULL, NULL, GENERIC_READ);
       WINAPI_VERIFY_NOT_NULL(hSCManager);
    
  • Using WINAPI_VERIFY_ERROR_SUCCESS to throw an exception in case of failure (the function returns an error code)
       UINT nRet = ::RegOpenKey(HKEY_LOCAL_MACHINE, pszPath, &hKey);
       WINAPI_VERIFY_ERROR_SUCCESS(nRet);
    
  • Catching CWinAPIException exceptions
       try
       {
          // some code which can throw CWinAPIException
       }
       catch(CWinAPIException* e)
       {
          e->ReportError();
          e->Delete();
       }
    
  • Prevent showing error code
       CWinAPIException::ShowErrorCode(false);
    

Demo application


ExceptionDemo is a simple SDI application that demonstrates how to use CWinAPIException. You can choose which additional info has to be shown (error code, source, and timestamp), then push "Test exception" button and enjoy.

Related articles



About the Author

Ovidiu Cucu

Graduated at "Gh. Asachi" Technical University - Iasi, Romania. Programming in C++ using Microsoft technologies since 1995. Microsoft MVP awardee since 2006. Moderator and article reviewer at Codeguru.com, the number one developer site. Co-founder of Codexpert.ro, a website dedicated to Romanian C++ developers.

Downloads

Comments

  • Do Herb Erectile Dysfunction Pills Offer Stronger And Rock Hard Erection?

    Posted by adeeffifielm on 06/21/2013 06:48am

    Why To Use Erectile Dysfunction Herbal Cure For Treating Impotence Problems? If medical causes and medications are ruled out, many times hormonal therapy will be attempted [url=http://rxhealth.pw ] viagra while working out [/url] see much more Masturbation Erectile Dysfunction Cures

    Reply
  • Good lookin exception class

    Posted by ahoodin on 07/27/2009 12:44pm

    Nice Ovi!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • You probably have several goals for your patient portal of choice. Is "community" one of them? With a bevy of vendors offering portal solutions, it can be challenging for a hospital to know where to start. Fortunately, YourCareCommunity helps ease the decision-making process. Read this white paper to learn more. "3 Ways Clinicians can Leverage a Patient Portal to Craft a Healthcare Community" is a published document owned by www.medhost.com

  • When it comes to desktops – physical or virtual – it's all about the applications. Cloud-hosted virtual desktops are growing fast because you get local data center-class security and 24x7 access with the complete personalization and flexibility of your own desktop. Organizations make five common mistakes when it comes to planning and implementing their application management strategy. This eBook tells you what they are and how to avoid them, and offers real-life case studies on customers who didn't let …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds