13 out of 37 rated this helpful - Rate this topic

Retrieving the Last-Error Code

When many system functions fail, they set the last-error code. If your application needs more details about an error, it can retrieve the last-error code using the GetLastError function and display a description of the error using the FormatMessage function.

The following example includes an error-handling function that prints the error message and terminates the process. The lpszFunction parameter is the name of the function that set the last-error code.


#include <windows.h>
#include <strsafe.h>

void ErrorExit(LPTSTR lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw); 
}

void main()
{
    // Generate an error

    if(!GetProcessId(NULL))
        ErrorExit(TEXT("GetProcessId"));
}


 

 

Send comments about this topic to Microsoft

Build date: 3/6/2012

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
error code
no goods fren
Free Pascal 2.4.4

Free Pascal, Windows API, FormatMessage, GetLastError
Free Pascal 2.4.4
This procedure displays a system error message, using the GetLastError,
FormatMessage, and LocalFree functions.

program DemoFormatMessage;
  uses
    Windows;                            {lets us use Windows API functions}
  (*
  This procedure displays a system error message, using the GetLastError,
  FormatMessage, and LocalFree functions.
  *)
  procedure DisplayErrorMessage;
    var
      GLEErrorCode : LongWord;          {GLE = GetLastError}
      (*
      function GetLastError
        (
        )
        : LongWord; StdCall;
      DWORD WINAPI GetLastError(void);
      *)
      FMMessageLength : LongWord;       {FM = FormatMessage}
      FMdwFlags : LongWord;
      FMlpSource : Pointer;
      FMdwMessageId : LongWord;
      FMdwLanguageId : LongWord;
      FMlpBuffer : PChar;
      FMnSize : LongWord;
      FMArguments : PChar;
      (*
      function FormatMessage
        (
          dwFlags : LongWord;
          lpSource : Pointer;
          dwMessageId : LongWord;
          dwLanguageId : LongWord;
          lpBuffer : PChar;
          nSize : LongWord;
          Arguments : PChar
        )
        : LongWord; StdCall;
      DWORD WINAPI FormatMessage(
        __in      DWORD dwFlags,
        __in_opt  LPCVOID lpSource,
        __in      DWORD dwMessageId,
        __in      DWORD dwLanguageId,
        __out     LPTSTR lpBuffer,
        __in      DWORD nSize,
        __in_opt  va_list *Arguments
      );
      *)
      LFReturn : LongWord;              {LF = LocalFree}
      LFhMem : LongWord;
      (*
      function LocalFree
        (
          hMem : LongWord
        )
        : LongWord; StdCall;
      HLOCAL WINAPI LocalFree(
        __in  HLOCAL hMem
      );
      *)
    begin {procedure DisplayErrorMessage}
      GLEErrorCode := GetLastError;
      WriteLn ('Error Code : ', GLEErrorCode);
      {}
      FMdwFlags :=
           FORMAT_MESSAGE_ALLOCATE_BUFFER
        or FORMAT_MESSAGE_FROM_SYSTEM
        or FORMAT_MESSAGE_IGNORE_INSERTS;
      FMlpSource := Pointer (0);
      FMdwMessageId := GLEErrorCode;
      FMdwLanguageId := 0;
      FMlpBuffer := Pointer (0);
      FMnSize := 0;
      FMArguments := Pointer (0);
      {}
      {Note how FMlpBuffer is used in the call to FormatMessage...}
      {}
      FMMessageLength :=
        FormatMessage
          (
            FMdwFlags,
            FMlpSource,
            FMdwMessageId,
            FMdwLanguageId,
            @FMlpBuffer,                {this works}
           (*
PChar (@FMlpBuffer), {this works, as well!}
            *)
            FMnSize,
            FMArguments
          );
      WriteLn ('Length of Error Message : ', FMMessageLength, ' bytes');
      if (FMMessageLength = 0)
        then
          begin {FormatMessage failed}
            WriteLn ('FormatMessage function failed.')
          end
        else
          begin {FormatMessage succeeded}
            write (FMlpBuffer);         {Display the error message}
            {}
            {now free the message buffer...}
            LFhMem := LongWord (FMlpBuffer);
            LFReturn := LocalFree (LFhMem);
            WriteLn ('LocalFree function returned : ', LFReturn);
            if (LFReturn = 0)
              then
                begin {LocalFree succeeded}
                  {}
                end
              else
                begin {LocalFree failed}
                  WriteLn ('LocalFree function failed.')
                end
          end
    end;  {procedure DisplayErrorMessage}
begin {program}
    {...}
    {insert here, a call to a Windows API function that generates an error}
DisplayErrorMessage;
{...}
end. {program}
This example violates the FormatMessage security warning
The documentation for FormatMessage contains the following security warning:

If this function is called without FORMAT_MESSAGE_IGNORE_INSERTS, the Arguments parameter must contain enough parameters to satisfy all insertion sequences in the message string, and they must be of the correct type. Therefore, do not use untrusted or unknown message strings with inserts enabled because they can contain more insertion sequences than Arguments provides, or those they may be of the wrong type. In particular, it is unsafe to take an arbitrary system error code returned from an API and use FORMAT_MESSAGE_FROM_SYSTEM without FORMAT_MESSAGE_IGNORE_INSERTS.