Click here to Skip to main content
15,897,518 members
Articles / Programming Languages / C++

Do Not Call GetLastError() !

Rate me:
Please Sign up or sign in to vote.
4.45/5 (22 votes)
27 Mar 2001CPOL 203.6K   3K   52   29
Use CWin32Error instead !! It encapsulates WIN32 error message strings with the error numbers. Has a smart-copy mechanism for passing objects by value, useful in exception-handling. Is TRACE() compatible!

Motivation

In your last project, how many times did you read the following in the MSDN help files:

If the function fails, the return value is NULL (or FALSE, or 0, or -1, or INVALID_HANDLE_VALUE).
To get extended error information, call GetLastError.

Then, while debugging, how many times did you:

  1. copy the current value of the error code from the variables window
  2. launch the Error Lookup tool
  3. paste the contents
  4. and hit a button on the tool

All of this just to see what the meaning of that error number was?

Or, how many times did you separately look up the FormatMessage documentation on MSDN (took time to swap the CDs too! :) ), just to copy and paste the code for retrieving error messages into your project?

Then, how many times did you wonder if it was worth introducing all those lines calling FormatMessage right in the middle of the main logic of your app?

Or, how many times did you recall the discussions of exceptions vs error codes?

Or, how many times did you have to explain the meaning of your own, home-grown, error strings to your marketing folks?

Why, coming to MFC, you even have a CPoint class, and a CSize class, but no CWin32Error class!!

That was so, until now! :)

CWin32Error Summary

A C++ class with a very small footprint that encapsulates both the WIN32 error-message strings and the error-code numbers returned by GetLastError(). Employs a smart-copy mechanism for minimal overheads while passing or returning objects by value. Provides DWORD and const char* conversions. Objects can also be sent to the TRACE() macro directly!

CWin32Error Sample Usage

Example 1: Exception Handling

void MyFunction( void ) throw CWin32Error
{
    if(! SomeWin32API())
    {
        // ::GetLastError() and ::FormatMessage()
        // automatically get called during construction.
        // Catch by value or by ref--the code stays the same.
        // Smart copying means you can rethrow the object by 
        // value as many times as you like!
        throw CWin32Error(); 
    }
}

void ClientToMyFunction( void )
{
    try
    {
        MyFunction();
    }
    catch( CWin32Error e ) // catching by value is OK (smart copying)
    {
        // Note: Automatic conversion to const TCHAR* type.
        ::OutputDebugTrace( e ); 
    }
}

Example 2: "Vanilla" Usage (No exception-handling)

The following code shows how a function can return a CWin32Error object. Smart copy means you can return objects even during the normal course of execution, without having to take an undue performance hit.

CWin32Error MyFunction( void ) 
{
    if( ! SomeWin32API() )
    {
        // Constructor gets last error and keeps the text 
        // of the error message ready.
        CWin32Error e; 

        // Don't have to call a member function even in 
        // MFC trace macro [i.e. no e.c_str() or (const char*) e]
        TRACE( "%s\n", e );

        return e;
    }
    // In Win32 API, the '0' value corresponds to the 
    // error string: "Operation completed successfully"
    // The error string is automatically taken from the OS 
    // in the returned CWin32Error object.

    return 0; // ctor taking unsigned int called here
}

Example 3: Simplest: As a message formatting class

The code given below shows how you can use CWin32Error purely to make the source-code look pretty!

void MyFunction( void ) 
{
    if( ! SomeWin32API() )
    {
        // If you want to retrieve the error code yourself...
        DWORD dwErr = ::GetLastError();

        // ...perhaps for some check on the code like this...
        if( AlertUser( dwErr ) )
        {
            // This form of CWin32Error ctor does NOT call 
            // ::GetLastError().

            CWin32Error e = dwErr; 
            
            // CWin32Error supplies const char* conversion
            AfxMessageBox( e );
        }
        // Else, forget prompting the user. 
        // Just return from the function...
        return;
    }
    // other code ...
}

CWin32Error Features

  • Is an incredibly small but enourmously useful C++ class.
  • Encapsulates the two basic Win32 APIs:
        GetLastError and
        FormatMessage.
  • Employs smart copy methods to minimize the overheads of memory allocation, retrieval of system error strings, and copying strings.
  • Has all member-functions inline. Just #include the Win32Error.h file.
  • Does not depend on MFC. Use freely with any C++ library.
  • Compiles under both UNICODE and MBCS.
  • Is very convenient and simple to use - in fact, the objects of this class are *best* created on the stack, and can be passed by value without undue performance hit.
  • Provides automatic conversion to const TCHAR* type. Pass objects, as they are, to MessageBox() or AfxMessageBox().
  • Supports the MFC TRACE macro. Pass objects to TRACE as they are - you don't have to call object.c_str() method or so. e.g. TRACE( "%s\n", e ); and not TRACE( "%s\n", e.c_str() );
  • Helps in taking advantage of the exception-handling features of the C++ language.

Documentation

The main source code is in only one file: Win32Error.h.

A console app demo is included in the download zip file.

Technical notes are included in the ReadMe.Win32Error.txt in the zip file.

Comments, suggestions, and bug reports are most welcome.

License

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


Written By
Other
India India
Ajit R. Jadhav is an engineer-cum-physicist from Pune, India. He completed a PhD on a topic from computational science and engineering in 2009. Earlier, he did a Diploma in Advanced Computing from C-DAC, Pune (1994), an MTech from IIT Madras (1987), and a Distinction Class BE from COEP, Pune (1983).

He has been programming Windows in C++ since 1994. He has also had many years of industrial, research and teaching experience in the past. Currently, he works as a consultant in computational mechanics with a small firm in Pune. History of science and philosophy continue to remain his other interests.

Comments and Discussions

 
PraiseThank you. :) Pin
Andrew Truckle27-Feb-16 2:20
professionalAndrew Truckle27-Feb-16 2:20 
GeneralMy vote of 1 Pin
Oracle2k22-Apr-12 12:19
Oracle2k22-Apr-12 12:19 
GeneralMy vote of 1 Pin
Oracle2k22-Apr-12 12:19
Oracle2k22-Apr-12 12:19 
GeneralFYI: two more articles on the subject Pin
Nick Alexeev25-Dec-10 11:17
professionalNick Alexeev25-Dec-10 11:17 
GeneralMultiple languages Pin
Milind Shingade31-May-06 19:08
Milind Shingade31-May-06 19:08 
GeneralMyOwn Error Handling Pin
Member 135487425-Nov-04 1:10
Member 135487425-Nov-04 1:10 
GeneralAlternative: WFC's wfc_get_error_string Pin
graham_k_200421-May-04 8:30
graham_k_200421-May-04 8:30 
GeneralThings that I don't like Pin
Sardaukar29-Mar-01 1:11
Sardaukar29-Mar-01 1:11 
GeneralRe: Things that I don't like Pin
Ajit Jadhav29-Mar-01 6:13
Ajit Jadhav29-Mar-01 6:13 
GeneralWay Ahead of You Pin
28-Mar-01 12:56
suss28-Mar-01 12:56 
GeneralRe: Way Ahead of You Pin
28-Mar-01 13:20
suss28-Mar-01 13:20 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav28-Mar-01 22:38
Ajit Jadhav28-Mar-01 22:38 
GeneralRe: Way Ahead of You Pin
30-Mar-01 7:20
suss30-Mar-01 7:20 
GeneralRe: Way Ahead of You Pin
30-Mar-01 7:21
suss30-Mar-01 7:21 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav30-Mar-01 7:59
Ajit Jadhav30-Mar-01 7:59 
GeneralRe: Way Ahead of You Pin
Mike Junkin2-Apr-01 3:27
Mike Junkin2-Apr-01 3:27 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav2-Apr-01 6:20
Ajit Jadhav2-Apr-01 6:20 
GeneralRe: Way Ahead of You Pin
Mike Junkin2-Apr-01 7:41
Mike Junkin2-Apr-01 7:41 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav2-Apr-01 14:48
Ajit Jadhav2-Apr-01 14:48 
GeneralRe: Way Ahead of You Pin
Mike Junkin3-Apr-01 5:01
Mike Junkin3-Apr-01 5:01 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav3-Apr-01 9:33
Ajit Jadhav3-Apr-01 9:33 
GeneralRe: Way Ahead of You Pin
Mike Junkin3-Apr-01 12:00
Mike Junkin3-Apr-01 12:00 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav4-Apr-01 4:09
Ajit Jadhav4-Apr-01 4:09 
GeneralRe: Way Ahead of You Pin
Mike Junkin4-Apr-01 6:29
Mike Junkin4-Apr-01 6:29 
GeneralRe: Way Ahead of You Pin
Ajit Jadhav4-Apr-01 17:09
Ajit Jadhav4-Apr-01 17:09 
Hi Mike,

-- And am I glad you see no fundamental problem with keeping DWORD and char* together Smile | :)

-- About the 1:1 mapping being a subset of all possible values. Yes. I do agree that it is a subset. (For the remainder subset, CWin32Error behaves gracefully.)

But within the subset where there are values, I always thought COM had 1:1. Do you have any salient examples that you can think of off-hand for 1 -> 0:1?

About user-messages: So long as they use ::GetLastError() and ::SetLastError(), their mapping had better be (i) 1:1, and (ii) not intruding into the set of predefined Win32 errors. Or else, I do not know how they could debug anything but the simplest "hello world" programs. (But let's not blame MS folks for this. Ensuring nonintrusiveness is really simple--all you do is define your own FACILITY bits.)

-- Frequency of usage as a clue into modelling concepts. Yes. I can see your point. In this context, this being a single, tiny and efficient class, all I have to say would really be a repetition--that there is no/only negligibly small additional cost; that at runtime you pay as you go, so that frequency becomes irrelevant. But yes, from modelling angle, it would be useful to think of that parameter.

-- About heap. Heap being a serializer for ultra-fast systems. Excellent point there.

A single-class "vendor" like me, however, simply cannot afford to think beyond a certain point. I did think about it more, because of the way you had put it in an earlier message--"different allocation strategies." Hmmm... I then just convinced myself that for this one-class effort, if they find the built-in new operator inefficient, they will have far many other, serious issues to look into. Things like CreateHeap; reserving, marking pages; page-faults; assumptions about m/c RAM and disk-access speeds... just gets ever deeper and wider. At any rate, it would be very hard to imagine how only CWin32Error but no other other structs/classes would come to face these new-operator related heap problems. Whatever they do to improve the new operator, any new new-handler scheme they install, CWin32Error will benefit from it. So, there. At any rate, I can't prevent ::FormatMessage from using the slower ::LocalAlloc, and that's where the bottleneck is. There is nothing more to be done to reduce *those* calls... unless an appwide mapping scheme is to be developed--which will be beyond the scope of a tiny single class.

-- Finally, about my C-style example. Oh, don't take it very seriously; it wasn't meant that way. Sometimes life just picks up a boring kind of seriousness out of nowhere (sic) and as such times it is useful to poke a little fun here and there... by deliberately blowing things out of proportion... A bit like parsing and shock therapy you had mentioned Big Grin | :-D

-- Alright. Let me try to get going with that guy's update again! I mean CWin32Error! (Sometimes working on the same source-code file, in front of that same stupid monitor, gets so boring!)

-- Ajit

Your project today is your great-grandchildrens' "ancestor clock."

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.