Поделиться через


Функция 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 000 байт, 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. Поток 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 в строке формата указывает первое значение в массиве Arguments ; %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", отформатированная выходная строка будет "Bill Bob Bill".

Однако при использовании описателя ширины и точности числа вставки не соответствуют напрямую входным аргументам. Например, вставка чисел для предыдущего примера может измениться на "%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 ). Затем форматируемой строкой будет "Bi Bob Bill".

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

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

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

 

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

Строка форматирования Результирующие выходные данные
%% Знак одного процента.
%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

См. также

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

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

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