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

C++ C# VB.NET

#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