Click here to Skip to main content
Click here to Skip to main content

Using FormatMessage

, 4 Feb 2002
Rate this:
Please Sign up or sign in to vote.
An example of one of the most effective uses of the the call to FormatMessage

Introduction

The FormatMessage API call is very powerful, and particularly useful for issuing all kinds of messages. This is not intended to be a full tutorial on using FormatMessage, but simply an example of one of the most effective uses of the the call. There is nothing more offensive than being presented with a message like the one below:

This is incomprehensible. The file cannot be opened. Why? For that matter, what file? The name the user types in is only part of the filename context; the rest relies on the current directory, which may not be what the user thinks it is. Errors like this generate unnecessary support calls to tech support departments, and consume a lot of time of the technical support people trying to determine what has gone wrong. A much better example of an error message is the next one. It tells what the application-level error is, what file was being considered, and the description of the error code.

In this case, I had created a read-only file junk.txt to induce the error on a Save command.

To make this work, I use the FormatMessage call. I then convert the value to a CString. If no error message is found, I handle the error by formatting the message with a particular string, which is stored in the STRINGTABLE

IDS_UNKNOWN_ERROR some value Unknown error 0x%08x (%d)

You will have to add this STRINGTABLE entry to your application. The string number doesn't matter. At the call site, you can do something like

    CStdioFile f;
    if(!f.Open(dlg.GetPathName(), CFile::modeWrite | CFile::modeCreate))
       { /* failed */
    DWORD err = ::GetLastError();
    CString errmsg = ErrorString(err);
        CString fmt;
        fmt.LoadString(IDS_OPEN_FAILED);
    CString s;
    s.Format(fmt, dlg.GetPathName(), errmsg);
    AfxMessageBox(s);
    return;
       } /* failed */

The message formatting string is stored as a resource in the STRINGTABLE. This allows for internationalization.

IDS_OPEN_FAILED some value File Open failed\n%s\n%s

One of the peculiar features of FormatMessage, which makes absolutely no sense at all, is that it appends a newline sequence to the message. This is rarely, if ever, of value, and as  far as I can tell, having worked in three other major operating systems that supported a FormatMessage equivalent, this seems to arise from some fundamental misunderstanding of the problem. In every single one of these systems, dating back to 1968, I have had to eliminate the newline sequence from the error string before it was usable! So I delete this newline sequence from the result of FormatMessage so the message can be placed in a MessageBox, CEdit, CListBox, or other such place and make sense. (The peculiar attitude seems to be that the designer of the error message should control this, when in fact it should either not be appended at all, or be an option flag that defaults to "off" in the call to retrieve the message).

Just for your information, if you want to get the error text while debugging, place in the watch window of the debugger the request

@ERR,hr

This is a screen snapshot of the watch window taken after the CStdioFile::Open call failed. As you can see, the error message is nicely explained to you, the programmer. When the error is something that needs to be displayed to the user, you can use my ErrorString function to get a nice CString. Note that even if you think the message code is of no use to the user, display it anyway. For example, a message of the form is actually very useful. Here is a simulated display of an AfxMessageBox. Your tech support people will be greatly aided.

Your Application Name Here
Unable to complete operation. Internal error.
Unexpected error code from network support.

( An attempt was made to establish a session to a network server, but there are already too many sessions established to that server).

Perhaps you did not expect this error and don't really know what to do when it occurs, but your tech support people could waste hours trying to track down a problem that is not really in your program, but an artifact of an overloaded server.

Here is the code of the function in its entirety: The download consists of a compilable .cpp file and the accompanying .h file.

CString ErrorString(DWORD err)
    {
     CString Error;
     LPTSTR s;
     if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            err,
            0,
            (LPTSTR)&s,
            0,
            NULL) == 0)
    { /* failed */
     // Unknown error code %08x (%d)
     CString fmt;
     CString t;
     fmt.LoadString(IDS_UNKNOWN_ERROR);
     t.Format(fmt, err, LOWORD(err));
     Error = t;
    } /* failed */
     else
    { /* success */
     LPTSTR p = _tcschr(s, _T('\r'));
     if(p != NULL)
        { /* lose CRLF */
         *p = _T('\0');
        } /* lose CRLF */
     Error = s;
     ::LocalFree(s);
    } /* success */
     return Error;
    } // ErrorString

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Joseph M. Newcomer

United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 4 PinmemberArun_angel17-Dec-12 3:10 
GeneralPerformance Question PinmemberRoss White17-Aug-09 5:52 
GeneralRe: Performance Question PinmemberJoseph M. Newcomer17-Aug-09 6:14 
Questionupdate, minor complaint, and request Pinmemberbkelly1324-Aug-08 15:27 
AnswerRe: update, minor complaint, and request PinmemberJoseph M. Newcomer24-Aug-08 18:41 
GeneralUse of language id PinmemberYuvarani_c11-Nov-03 18:13 
GeneralRe: Use of language id PinmemberJoseph M. Newcomer16-Nov-03 11:07 
GeneralFormatMessage and %%% PinmemberArmen Hakobyan17-Nov-02 9:33 
GeneralRe: FormatMessage and %%% PinmemberJoseph M. Newcomer18-Nov-02 5:46 
GeneralGood code, bad design PinmemberJim A. Johnson6-Feb-02 6:35 
GeneralRe: Good code, bad design Pinmemberpeterchen6-Feb-02 8:08 
GeneralRe: Good code, bad design PinmemberJim A. Johnson6-Feb-02 9:01 
GeneralRe: Good code, bad design PinmemberKovalski8-Mar-07 4:50 
GeneralRe: Good code, bad design PinmemberJoseph M. Newcomer16-Feb-02 11:43 
GeneralYou forgot something important PinmemberAndreas Saurwein5-Feb-02 0:27 
GeneralRe: You forgot something important PinmemberJoseph M. Newcomer16-Feb-02 17:16 
GeneralRe: You forgot something important PinmemberAndreas Saurwein16-Feb-02 21:55 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140709.1 | Last Updated 5 Feb 2002
Article Copyright 2002 by Joseph M. Newcomer
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid