FormatMessage (kernel32)
Last changed: -84.110.53.106

.
Summary

C# Signature:

[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
   uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer,
   uint nSize, IntPtr Arguments);

// the version, the sample is built upon:
[DllImport("Kernel32.dll", SetLastError=true)]
static extern uint FormatMessage( uint dwFlags, IntPtr lpSource,
   uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
   uint nSize, IntPtr pArguments);

// the parameters can also be passed as a string array:
[DllImport("Kernel32.dll", SetLastError=true)]
static extern uint FormatMessage( uint dwFlags, IntPtr lpSource,
   uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
   uint nSize, string[] Arguments);

// see the sample code
[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, uint nSize, string[] Arguments);

VB.NET Signature:

<DllImport("Kernel32.dll", EntryPoint:="FormatMessageW", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function FormatMessage(ByVal dwFlags As Integer, ByRef lpSource As IntPtr, ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByRef lpBuffer As [String], ByVal nSize As Integer, ByRef Arguments As IntPtr) As Integer
End Function

User-Defined Types:

None.

Notes:

To have FormatMessage substitute %1, %2, etc. with arguments you pass it, declare FormatMessage with a string[] for the last parameter and just pass a normal C# string array. You need to include FORMAT_MESSAGE_ARGUMENT_ARRAY in the dwFlags parameter for this to work.

Tips & Tricks:

If you are trying use FormatMessage to "decode" an error from Marshal.GetLastWin32Error, go take a look at Marshal.ThrowExceptionForHR (http://msdn.microsoft.com/en-us/library/ckxcyk36(v=VS.80).aspx).

Sample Code:

    // from header files
    const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
    const uint FORMAT_MESSAGE_IGNORE_INSERTS  = 0x00000200;
    const uint FORMAT_MESSAGE_FROM_SYSTEM    = 0x00001000;
    const uint FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
    const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
    const uint FORMAT_MESSAGE_FROM_STRING = 0x00000400;

    int nLastError= Marshal.GetLastWin32Error();

    IntPtr lpMsgBuf= IntPtr.Zero;

    uint dwChars= FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        IntPtr.Zero,
        (uint)nLastError,
        0, // Default language
        ref lpMsgBuf,
        0,
        IntPtr.Zero);
    if (dwChars==0)
    {
        // Handle the error.
        int le= Marshal.GetLastWin32Error();
        return null;
    }

    string sRet= Marshal.PtrToStringAnsi(lpMsgBuf);

    // Free the buffer.
    lpMsgBuf= LocalFree( lpMsgBuf );
    return sRet;

    // add for the forth signature
    try
    {
        StringBuilder msgBuilder = new StringBuilder(101);

        string formatExpression = "%1,%2%!";
        string[] formatArgs = new string[] { "Hello", "world" };

        IntPtr formatPtr = Marshal.StringToHGlobalAnsi(formatExpression);

        //must specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag when pass an array
        uint length = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, formatPtr, 0, 0, msgBuilder, 101, formatArgs);

        if (length == 0)
        {
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, (uint)Marshal.GetLastWin32Error(), 0, msgBuilder, 101, null);

            Console.WriteLine("Error:" + msgBuilder.ToString());
        }
        else
        {
            Console.WriteLine("Format result:" + msgBuilder.ToString() + ", length:" + length.ToString());
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

Alternative Managed API:

This functionality is also given by System.ComponentModel.Win32Exception:

string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
Console.WriteLine(errorMessage);

Yet the sample might still be useful for messages not provided by the system.

Documentation