Функция FormatMessage (winbase.h)

Форматирует строку сообщения. Для функции требуется определение сообщения в качестве входных данных. Определение сообщения может поступать из буфера, переданного в функцию. Он может поступать из ресурса таблицы сообщений в уже загруженном модуле. Или вызывающий объект может попросить функцию выполнить поиск ресурсов таблицы сообщений системы для определения сообщения. Функция находит определение сообщения в ресурсе таблицы сообщений на основе идентификатора сообщения и идентификатора языка. Функция копирует отформатированный текст сообщения в выходной буфер, обрабатывая все внедренные последовательности вставки при необходимости.

Синтаксис

DWORD FormatMessage(
  [in]           DWORD   dwFlags,
  [in, optional] LPCVOID lpSource,
  [in]           DWORD   dwMessageId,
  [in]           DWORD   dwLanguageId,
  [out]          LPTSTR  lpBuffer,
  [in]           DWORD   nSize,
  [in, optional] va_list *Arguments
);

Параметры

[in] dwFlags

Параметры форматирования и интерпретация параметра lpSource . Байт dwFlags с низким порядком определяет, как функция обрабатывает разрывы строк в выходном буфере. Байт низкого порядка также может указывать максимальную ширину форматируемой выходной строки.

Этот параметр может быть одним или несколькими из следующих значений.

Значение Значение
FORMAT_MESSAGE_ALLOCATE_BUFFER
0x00000100
Функция выделяет буфер достаточно большой для хранения отформатированного сообщения и помещает указатель на выделенный буфер по адресу, указанному lpBuffer. Параметр lpBuffer является указателем на LPTSTR; Необходимо привести указатель к LPTSTR (например, (LPTSTR)&lpBuffer). Параметр nSize указывает минимальное количество TCHAR , выделяемых для буфера выходных сообщений. Вызывающий объект должен использовать функцию LocalFree , чтобы освободить буфер, если он больше не нужен.

Если длина отформатированного сообщения превышает 128 КБ, formatMessage завершится ошибкой, а последующий вызов GetLastError вернет ERROR_MORE_DATA.

В предыдущих версиях Windows это значение было недоступно для использования при компиляции приложений Магазина Windows. По Windows 10 это значение можно использовать.

Windows Server 2003 и Windows XP:

Если длина отформатированного сообщения превышает 128 КБ, FormatMessage не будет автоматически завершатся ошибкой ERROR_MORE_DATA.

FORMAT_MESSAGE_ARGUMENT_ARRAY
0x00002000
Параметр Arguments не является структурой va_list , но является указателем на массив значений, представляющих аргументы.

Этот флаг нельзя использовать с 64-разрядными целыми значениями. При использовании 64-разрядного целого числа необходимо использовать структуру va_list .

FORMAT_MESSAGE_FROM_HMODULE
0x00000800
Параметр lpSource — это дескриптор модуля, содержащий ресурсы таблицы сообщений для поиска. Если этот дескриптор lpSource имеет значение NULL, будет выполнен поиск файла образа приложения текущего процесса. Этот флаг нельзя использовать с FORMAT_MESSAGE_FROM_STRING.

Если модуль не имеет ресурса таблицы сообщений, функция завершается ошибкой с ERROR_RESOURCE_TYPE_NOT_FOUND.

FORMAT_MESSAGE_FROM_STRING
0x00000400
Параметр lpSource — это указатель на строку, завершающуюся значением NULL, которая содержит определение сообщения. Определение сообщения может содержать последовательности вставки так же, как и текст сообщения в ресурсе таблицы сообщений. Этот флаг нельзя использовать с FORMAT_MESSAGE_FROM_HMODULE или FORMAT_MESSAGE_FROM_SYSTEM.
FORMAT_MESSAGE_FROM_SYSTEM
0x00001000
Функция должна искать в запрошенном сообщении ресурсы таблицы системных сообщений. Если этот флаг указан с помощью FORMAT_MESSAGE_FROM_HMODULE, функция выполняет поиск в таблице системных сообщений, если сообщение не найдено в модуле, указанном в lpSource. Этот флаг нельзя использовать с FORMAT_MESSAGE_FROM_STRING.

Если этот флаг указан, приложение может передать результат функции GetLastError , чтобы получить текст сообщения для системной ошибки.

FORMAT_MESSAGE_IGNORE_INSERTS
0x00000200
Последовательности вставки в определение сообщения, например %1, должны игнорироваться и передаваться в выходной буфер без изменений. Этот флаг полезен для получения сообщения для последующего форматирования. Если этот флаг задан, параметр Arguments игнорируется.
 

Байт dwFlags с низким порядком может указывать максимальную ширину форматируемой выходной строки. Ниже приведены возможные значения байтов низкого порядка.

Значение Значение
0
Ограничения ширины линии вывода отсутствуют. Функция сохраняет разрывы строк, находящиеся в тексте определения сообщения, в выходной буфер.
FORMAT_MESSAGE_MAX_WIDTH_MASK
0x000000FF
Функция игнорирует регулярные разрывы строк в тексте определения сообщения. Функция сохраняет жестко закодированные разрывы строк в тексте определения сообщения в выходном буфере. Функция не создает новых разрывов строк.
 

Если байт низкого порядка является ненулевое значение, отличное от FORMAT_MESSAGE_MAX_WIDTH_MASK, оно указывает максимальное число символов в выходной строке. Функция игнорирует регулярные разрывы строк в тексте определения сообщения. Функция никогда не разделяет строку, разделенную пробелами в разрыве строки. Функция сохраняет жестко закодированные разрывы строк в тексте определения сообщения в выходном буфере. Жестко закодированные разрывы строк кодируются с помощью escape-последовательности %n.

[in, optional] lpSource

Расположение определения сообщения. Тип этого параметра зависит от параметров в параметре dwFlags .

Dwflags Параметр Значение
FORMAT_MESSAGE_FROM_HMODULE
0x00000800
Дескриптор модуля, содержащего таблицу сообщений для поиска.
FORMAT_MESSAGE_FROM_STRING
0x00000400
Указатель на строку, состоящую из неформатированного текста сообщения. Она будет проверена на наличие вставок и отформатирована соответствующим образом.
 

Если ни у того из этих флагов не задано в dwFlags, то lpSource игнорируется.

[in] dwMessageId

Идентификатор сообщения для запрошенного сообщения. Этот параметр игнорируется, если dwFlags включает FORMAT_MESSAGE_FROM_STRING.

[in] dwLanguageId

Идентификатор языка для запрошенного сообщения. Этот параметр игнорируется, если dwFlags включает FORMAT_MESSAGE_FROM_STRING.

Если передать определенный LANGID в этом параметре, FormatMessage вернет сообщение только для этого LANGID . Если функция не может найти сообщение для этого LANGID, она задает для Last-Error значение ERROR_RESOURCE_LANG_NOT_FOUND. Если передать ноль, FormatMessage ищет сообщение для LANGID в следующем порядке:

  1. Нейтральная языковая
  2. Thread LANGID на основе значения языкового стандарта потока
  3. Пользователь по умолчанию LANGID, основанный на значении языкового стандарта пользователя по умолчанию
  4. Системный стандарт LANGID по умолчанию на основе значения языкового стандарта по умолчанию системы
  5. Английский (США)
Если FormatMessage не находит сообщение для любого из предыдущих LANGID, он возвращает любую строку сообщения языка, которая присутствует. Если это не удается, возвращается ERROR_RESOURCE_LANG_NOT_FOUND.

[out] lpBuffer

Указатель на буфер, получающий строку, завершающуюся значением NULL, указывающую форматированное сообщение. Если dwFlags включает FORMAT_MESSAGE_ALLOCATE_BUFFER, функция выделяет буфер с помощью функции LocalAlloc и помещает указатель на буфер по адресу, указанному в lpBuffer.

Размер этого буфера не может превышать 64 КБ.

[in] nSize

Если флаг FORMAT_MESSAGE_ALLOCATE_BUFFER не задан, этот параметр указывает размер выходного буфера в TCHAR. Если задан FORMAT_MESSAGE_ALLOCATE_BUFFER , этот параметр указывает минимальное количество TCHAR , выделяемых для выходного буфера.

Размер выходного буфера не может превышать 64 КБ.

[in, optional] Arguments

Массив значений, используемых в качестве значений вставки в форматируемом сообщении. %1 в строке формата указывает первое значение в массиве аргументов ; значение %2 указывает второй аргумент; и так далее.

Интерпретация каждого значения зависит от сведений о форматировании, связанных с вставкой в определении сообщения. По умолчанию каждое значение обрабатывается как указатель на строку, завершаемую значением NULL.

По умолчанию параметр Arguments имеет тип va_list*, который является типом данных, зависящим от языка и реализации, для описания переменного числа аргументов. Состояние аргумента va_list не определено при возвращении из функции. Чтобы снова использовать va_list , удалите указатель списка аргументов переменной с помощью va_end и повторно инициализируйте его с помощью va_start.

Если у вас нет указателя типа va_list*, укажите флаг FORMAT_MESSAGE_ARGUMENT_ARRAY и передайте указатель на массив DWORD_PTR значений; эти значения являются входными данными для сообщения, отформатированного в качестве значений вставки. Каждая вставка должна иметь соответствующий элемент в массиве.

Возвращаемое значение

Если функция завершается успешно, возвращаемое значение — это число TCHAR , хранящихся в выходном буфере, за исключением завершающего символа NULL.

Если функция выполняется неудачно, возвращается нулевое значение. Дополнительные сведения об ошибке можно получить, вызвав GetLastError.

Комментарии

В тексте сообщения поддерживается несколько escape-последовательностей для динамического форматирования сообщения. Эти escape-последовательности и их значения показаны в следующих таблицах. Все escape-последовательности начинаются с символа процента (%).

Escape-последовательность Значение
%0 Завершает текстовую строку сообщения без символа в конце новой строки. Эту escape-последовательность можно использовать для создания длинных строк или завершения самого сообщения без символа новой строки. Это полезно для сообщений с запросами.
%n! строка форматирования! Определяет последовательность вставки. Значение n может находиться в диапазоне от 1 до 99. Строка формата (которая должна быть окружена восклицательными знаками) является необязательной и по умолчанию имеет значение !s! , если не определено. Дополнительные сведения см. в разделе "Поля спецификации форматирования".

Строка формата может включать описатель ширины и точности для строк и описатель ширины для целых чисел. Используйте звездочку (), чтобы указать ширину и точность. Например, %1!. *s! или %1!*u!.

Если не используются описатели ширины и точности, числа вставки соответствуют непосредственно входным аргументам. Например, если исходная строка — "%1 %2 %1", а входные аргументы — "Bill" и "Bob", то форматированная выходная строка — "Билл Боб Билл".

Однако если используется описатель ширины и точности, числа вставки не соответствуют непосредственно входным аргументам. Например, числа вставок для предыдущего примера могут измениться на "%1!*.*s! %4 %5!*s!".

Числа вставки зависят от того, используется ли массив аргументов (FORMAT_MESSAGE_ARGUMENT_ARRAY) или va_list. Для массива аргументов следующий номер вставки равен n+2 , если предыдущая строка формата содержала одну звездочку и n+3 , если были указаны две звездочки. Для va_list следующее число вставки равно n+1 , если в предыдущей строке формата содержится одна звездочка и n+2 , если были указаны две звездочки.

Если вы хотите повторить "Bill", как в предыдущем примере, аргументы должны включать "Bill" дважды. Например, если исходная строка — "%1!*.*s! %4 %5!*s!", аргументы могут быть: 4, 2, Билл, Боб, 6, Билл (при использовании флага FORMAT_MESSAGE_ARGUMENT_ARRAY ). Форматированная строка будет "Би Боб Билл".

Повторяющиеся числа вставки, если исходная строка содержит описатели ширины и точности, могут не дать ожидаемых результатов. Если вы заменили %5 %1, функция попытается напечатать строку по адресу 6 (скорее всего, это приведет к нарушению доступа).

Описатели формата с плавающей запятой ( e, E, f и g) не поддерживаются. Обходной путь — использовать функцию StringCchPrintf для форматирования числа с плавающей запятой во временный буфер, а затем использовать этот буфер в качестве строки вставки.

Вставки, использующие префикс I64, обрабатываются как два 32-разрядных аргумента. Они должны использоваться до использования последующих аргументов. Обратите внимание, что вместо этого префикса можно использовать StringCchPrintf .

 

Любой другой недигитный символ, следующий за символом процента, отформатирован в выходном сообщении без символа процента. Ниже приводятся некоторые примеры.

Строка форматирования Итоговые выходные данные
%% Знак единого процента.
%B Одно пространство. Эту строку формата можно использовать для обеспечения соответствующего количества конечных пробелов в текстовой строке сообщения.
%. Один период. Эту строку формата можно использовать для включения одного периода в начало строки без прекращения определения текста сообщения.
%! Один восклицательный знак. Эту строку формата можно использовать для включения восклицательного знака сразу после вставки без ошибок в начале строки формата.
%n Жесткий разрыв строки при возникновении строки формата в конце строки. Эта строка формата полезна, если FormatMessage предоставляет регулярные разрывы строк, чтобы сообщение соответствовало определенной ширине.
%r Жесткий возврат каретки без символа новой линии.
%t Одна вкладка.
 

Замечания по безопасности

Если эта функция вызывается без FORMAT_MESSAGE_IGNORE_INSERTS, параметр Arguments должен содержать достаточно параметров для удовлетворения всех последовательностей вставки в строке сообщения, и они должны иметь правильный тип. Поэтому не используйте ненадежные или неизвестные строки сообщений с включенными вставками, так как они могут содержать больше последовательностей вставки, чем аргументы , или те, которые могут иметь неправильный тип. В частности, небезопасно принимать произвольный системный код ошибки, возвращаемый из API, и использовать FORMAT_MESSAGE_FROM_SYSTEM без FORMAT_MESSAGE_IGNORE_INSERTS.

Примеры

Функцию FormatMessage можно использовать для получения строк сообщения об ошибке для системных кодов ошибок, возвращаемых Методом GetLastError. Пример см. в разделе "Получение кода Last-Error".

В следующем примере показано, как использовать массив аргументов и описатели ширины и точности.
#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <stdio.h>

void main(void)
{
    LPWSTR pMessage = L"%1!*.*s! %4 %5!*s!";
    DWORD_PTR pArgs[] = { (DWORD_PTR)4, (DWORD_PTR)2, (DWORD_PTR)L"Bill",  // %1!*.*s! refers back to the first insertion string in pMessage
         (DWORD_PTR)L"Bob",                                                // %4 refers back to the second insertion string in pMessage
         (DWORD_PTR)6, (DWORD_PTR)L"Bill" };                               // %5!*s! refers back to the third insertion string in pMessage
    const DWORD size = 100+1;
    WCHAR buffer[size];


    if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                       pMessage, 
                       0,
                       0,
                       buffer, 
                       size, 
                       (va_list*)pArgs))
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
        return;
    }

    // Buffer contains "  Bi Bob   Bill".
    wprintf(L"Formatted message: %s\n", buffer);
}


В следующем примере показано, как реализовать предыдущий пример с помощью va_list.

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <stdio.h>

LPWSTR GetFormattedMessage(LPWSTR pMessage, ...);

void main(void)
{
    LPWSTR pBuffer = NULL;
    LPWSTR pMessage = L"%1!*.*s! %3 %4!*s!";

    // The variable length arguments correspond directly to the format
    // strings in pMessage.
    pBuffer = GetFormattedMessage(pMessage, 4, 2, L"Bill", L"Bob", 6, L"Bill");
    if (pBuffer)
    {
        // Buffer contains "  Bi Bob   Bill".
        wprintf(L"Formatted message: %s\n", pBuffer);
        LocalFree(pBuffer);
    }
    else
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
    }
}

// Formats a message string using the specified message and variable
// list of arguments.
LPWSTR GetFormattedMessage(LPWSTR pMessage, ...)
{
    LPWSTR pBuffer = NULL;

    va_list args = NULL;
    va_start(args, pMessage);

    FormatMessage(FORMAT_MESSAGE_FROM_STRING |
                  FORMAT_MESSAGE_ALLOCATE_BUFFER,
                  pMessage, 
                  0,
                  0,
                  (LPWSTR)&pBuffer, 
                  0, 
                  &args);

    va_end(args);

    return pBuffer;
}

Требования

   
Минимальная версия клиента Windows XP [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winbase.h (включая Windows.h)
Библиотека Kernel32.lib
DLL Kernel32.dll

См. также

Функции обработки ошибок

Компилятор сообщений

Таблицы сообщений