GetLastError
Retrieves the last error value set by a thread.
Syntax
DWORD GetLastError(void);
Parameters
This function does not take any parameters.
Return value
The return value is the last error code set by a thread. A return value of 0 typically indicates success. However, the last-error code is not always zero when a function succeeds. If a function's documentation specifies a last-error code value, that value is used. Otherwise, the last-error code is set to a system-defined value when a function fails. To get the extended error information, call GetLastError.
Remarks
The error code is stored on a thread-local basis. Each thread maintains its own last-error code.
Most functions that return an error code set the last-error code when they fail. Some functions do not set the last-error code when they succeed. If a function's documentation does not explicitly state that it sets the last-error code, you can assume that it does not set it when it succeeds.
To retrieve the system-defined error message string for the last-error code, use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTEM flag.
Requirements
| Tool Name | Value |
|---|---|
| Minimum supported client | Windows 2000 Professional |
| Minimum supported server | Windows 2000 Server |
| Header | winbase.h (include Windows.h) |
| Library | Kernel32.lib |
| DLL | Kernel32.dll |
Example
#include <windows.h> #include <iostream> int main() { // Attempt an operation that is likely to fail (e.g., opening a non-existent file) HANDLE hFile = CreateFile( L"non_existent_file.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { DWORD dwError = GetLastError(); std::wcout << L"Error creating file. Last error code: " << dwError << std::endl; // Use FormatMessage to get the error string LPWSTR buffer = NULL; DWORD dwChars = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&buffer, 0, NULL ); if (buffer != NULL) { std::wcout << L"Error message: " << buffer << std::endl; LocalFree(buffer); // Free the buffer allocated by FormatMessage } } else { CloseHandle(hFile); // Clean up if somehow the file was created std::wcout << L"File opened successfully." << std::endl; } return 0; }using System; using System.Runtime.InteropServices; using System.Text; public class Example { [DllImport("kernel32.dll")] public static extern IntPtr CreateFile( string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile ); [DllImport("kernel32.dll", SetLastError = true)] public static extern uint GetLastError(); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern uint FormatMessage( uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, out string lpBuffer, uint nSize, IntPtr Arguments ); const uint GENERIC_READ = 0x80000000; const uint OPEN_EXISTING = 3; const uint FILE_ATTRIBUTE_NORMAL = 0x80; const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; public static void Main(string[] args) { IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); IntPtr hFile = CreateFile( "non_existent_file.txt", GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero ); if (hFile == INVALID_HANDLE_VALUE) { uint dwError = GetLastError(); Console.WriteLine($"Error creating file. Last error code: {dwError}"); string errorMsg = ""; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, IntPtr.Zero, dwError, 0, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) out errorMsg, 0, IntPtr.Zero ); if (!string.IsNullOrEmpty(errorMsg)) { Console.WriteLine($"Error message: {errorMsg.Trim()}"); } } else { // CloseHandle is not directly exported in C#, managed code handles this. // But for demonstration, we can pretend to close. Console.WriteLine("File opened successfully (this should not happen with the example filename)."); } } }Imports System Imports System.Runtime.InteropServices Public Class Example <DllImport("kernel32.dll")> Public Shared Function CreateFile( ByVal lpFileName As String, ByVal dwDesiredAccess As UInteger, ByVal dwShareMode As UInteger, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As UInteger, ByVal dwFlagsAndAttributes As UInteger, ByVal hTemplateFile As IntPtr ) As IntPtr End Function <DllImport("kernel32.dll", SetLastError:=True)> Public Shared Function GetLastError() As UInteger End Function <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> Public Shared Function FormatMessage( ByVal dwFlags As UInteger, ByVal lpSource As IntPtr, ByVal dwMessageId As UInteger, ByVal dwLanguageId As UInteger, ByRef lpBuffer As String, ByVal nSize As UInteger, ByVal Arguments As IntPtr ) As UInteger End Function Private Const GENERIC_READ As UInteger = &H80000000UI Private Const OPEN_EXISTING As UInteger = 3UI Private Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80UI Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER As UInteger = &H00000100UI Private Const FORMAT_MESSAGE_FROM_SYSTEM As UInteger = &H00001000UI Private Const FORMAT_MESSAGE_IGNORE_INSERTS As UInteger = &H00000200UI Public Shared Sub Main(args As String()) Dim INVALID_HANDLE_VALUE As New IntPtr(-1) Dim hFile As IntPtr = CreateFile( "non_existent_file.txt", GENERIC_READ, 0UI, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero ) If hFile = INVALID_HANDLE_VALUE Then Dim dwError As UInteger = GetLastError() Console.WriteLine($"Error creating file. Last error code: {dwError}") Dim errorMsg As String = "" FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, IntPtr.Zero, dwError, 0UI, ' MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) errorMsg, 0UI, IntPtr.Zero ) If Not String.IsNullOrEmpty(errorMsg) Then Console.WriteLine($"Error message: {errorMsg.Trim()}") End If Else ' CloseHandle is not directly exported in VB.NET, managed code handles this. ' But for demonstration, we can pretend to close. Console.WriteLine("File opened successfully (this should not happen with the example filename).") End If End Sub End Class