c++windowserror-handlingformatmessage

How should I use FormatMessage() properly in C++?


Without:

How can I use FormatMessage() to get the error text for a HRESULT?

 HRESULT hresult = application.CreateInstance("Excel.Application");

 if (FAILED(hresult))
 {
     // what should i put here to obtain a human-readable
     // description of the error?
     exit (hresult);
 }

Solution

  • Here's the proper way to get an error message back from the system for an HRESULT (named hresult in this case, or you can replace it with GetLastError()):

    LPTSTR errorText = NULL;
    
    FormatMessage(
       // use system message tables to retrieve error text
       FORMAT_MESSAGE_FROM_SYSTEM
       // allocate buffer on local heap for error text
       |FORMAT_MESSAGE_ALLOCATE_BUFFER
       // Important! will fail otherwise, since we're not 
       // (and CANNOT) pass insertion parameters
       |FORMAT_MESSAGE_IGNORE_INSERTS,  
       NULL,    // unused with FORMAT_MESSAGE_FROM_SYSTEM
       hresult,
       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
       (LPTSTR)&errorText,  // output 
       0, // minimum size for output buffer
       NULL);   // arguments - see note 
       
    if ( NULL != errorText )
    {
       // ... do something with the string `errorText` - log it, display it to the user, etc.
    
       // release memory allocated by FormatMessage()
       LocalFree(errorText);
       errorText = NULL;
    }
    

    The key difference between this and David Hanak's answer is the use of the FORMAT_MESSAGE_IGNORE_INSERTS flag. MSDN is a bit unclear on how insertions should be used, but Raymond Chen notes that you should never use them when retrieving a system message, as you've no way of knowing which insertions the system expects.

    FWIW, if you're using Visual C++ you can make your life a bit easier by using the _com_error class:

    {
       _com_error error(hresult);
       LPCTSTR errorText = error.ErrorMessage();
       
       // do something with the error...
    
       //automatic cleanup when error goes out of scope
    }
    

    Not part of MFC or ATL directly as far as I'm aware.