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
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}
- 7/25/2011
- Brad Dinte
- 8/23/2011
- Brad Dinte
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.
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.
- 4/13/2007
- fletcherdunn
- 6/27/2010
- Thomas Lee