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


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

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

Синтаксис

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

Параметры

[in] dwFlags

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

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

Ценность Значение
FORMAT_MESSAGE_ALLOCATE_BUFFER
0x00000100
Функция выделяет буфер достаточно большой для хранения отформатированного сообщения и помещает указатель на выделенный буфер по адресу, указанному lpBuffer. Параметр lpBuffer — это указатель на LPTSTR; Указатель необходимо привести к LPTSTR (например, ). Параметр nSize указывает минимальное количество TCHARs для выделения для буфера выходных сообщений. Вызывающий объект должен использовать функцию 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
Параметр аргументов не является va_list структурой, но является указателем на массив значений, представляющих аргументы.

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

FORMAT_MESSAGE_FROM_HMODULE
0x00000800
Параметр lpSource — это дескриптор модуля, содержащий ресурсы таблицы сообщений для поиска. Если этот дескриптор lpSource lpSourceNULL, будет выполнен поиск по файлу образа приложения текущего процесса. Этот флаг нельзя использовать с 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 не находит сообщение для любой из предыдущих lanGIDs, она возвращает любую строку сообщения языка, которая присутствует. Если это не удается, возвращается ERROR_RESOURCE_LANG_NOT_FOUND.

[out] lpBuffer

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

Этот буфер не может быть больше 64 КБ.

[in] nSize

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

Выходной буфер не может быть больше 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; эти значения представляют собой входные данные для сообщения, отформатированного в виде значений вставки. Каждая вставка должна иметь соответствующий элемент в массиве.

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

Если функция выполнена успешно, возвращаемое значение равно числу TCHARs, хранящимся в выходном буфере, за исключением завершающего символа 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, если были указаны две звездочки.

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

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

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

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

 

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

Строка форматирования Результирующий результат
%% Единый знак процента.
% пространства Одно пространство. Эту строку форматирования можно использовать для обеспечения соответствующего количества конечных пробелов в текстовой строке сообщения.
%. Один период. Эту строку форматирования можно использовать для включения одного периода в начале строки без прекращения определения текста сообщения.
%! Один восклицательный знак. Эту строку формата можно использовать для включения восклицательного знака сразу после вставки без ошибок в начале строки формата.
%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;
}

Заметка

Заголовок winbase.h определяет FormatMessage как псевдоним, который автоматически выбирает версию ANSI или Юникод этой функции на основе определения константы препроцессора ЮНИКОДа. Сочетание использования псевдонима, нейтрального для кодирования, с кодом, не зависящим от кодирования, может привести к несоответствиям, которые приводят к ошибкам компиляции или среды выполнения. Дополнительные сведения см. в соглашениях о прототипах функций.

Требования

Требование Ценность
минимальные поддерживаемые клиентские Windows XP [классические приложения | Приложения UWP]
минимальный поддерживаемый сервер Windows Server 2003 [классические приложения | Приложения UWP]
целевая платформа Виндоус
заголовка winbase.h (включая Windows.h)
библиотеки Kernel32.lib
DLL Kernel32.dll

См. также

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

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

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