Функция FormatMessage

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

Синтаксис

DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId,
  __in      DWORD dwLanguageId,
  __out     LPTSTR lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list* Arguments
);
 

Параметры

dwFlags

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

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

Значение

Предназначение

FORMAT_MESSAGE_ALLOCATE_BUFFER
0x00000100
Параметр lpBuffer - указатель на указатель PVOID, и что параметр nSize определяет минимальное число TCHARs, чтобы назначить для буфера выходное сообщение. Функция назначает буфер, достаточно большой, чтобы содержать форматированное сообщение и помещает указатель в выделенный буфер по адресу, указанному в параметре lpBuffer. Вызывающая программа (вызывающий модуль) должна использовать функцию LocalFree для освобождения буфера, когда он больше не нужен.
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 - указатель на строку с завершающим нулем, который содержит определение сообщения. Определение сообщения может содержать в себе последовательности вставок, а так же может содержать текст сообщения в ресурсе таблицы сообщений. Этот флажок не может использоваться с флажками 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
Последовательности вставки в определении сообщения должны игнорироваться и передаваться неизменными в буфер выводимых данных. Этот флажок полезен для выборки сообщения для более позднего форматирования. Если это флажок установлен, параметр Arguments игнорируется.

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

Значение

Предназначение

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

 

lpSource

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

Установка dwFlags

Предназначение

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

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

dwMessageId

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

dwLanguageId

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

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

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

Если FormatMessage не локализирует сообщения для какого-либо предшествующего LANGIDs, то она возвращает любую языковую строку сообщения, которая присутствует. Если функция завершается ошибкой, то возвращает значение ERROR_RESOURCE_LANG_NOT_FOUND.

lpBuffer

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

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

nSize

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

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

Arguments

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

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

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

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

Windows Me/98/95:  Никакая отдельная строка включения не может выйти за пределы 1023 символов по длине.

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

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

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

Замечания

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

ESC-последовательности

Предназначение

%0

Завершает строку текста сообщения без замыкающего знака новой строки. Эта ESC-последовательность может быть использована для создания длинных строк или для завершения сообщения непосредственно без замыкающего знака новой строки. Это полезно для сообщений приглашения для ввода в командной строке.

%n!format string!

Идентифицирует вставку. Значение n может быть в диапазоне от 1 до 99. Форматирующая строка, которая должна быть окружена восклицательными знаками, является дополнительной (необязательной) и значениями по умолчанию !s!, если не определены. Дополнительную информацию смотри в статье Поля спецификации формата.

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

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

Однако, если Вы используете спецификатор ширины и точности, числа вставки не соответствуют непосредственно вводимым параметрам. Например, числа вставки для предыдущего примера могут поменяться на "%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 вместо этого префикса.

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

Форматирующая строка

Окончательный вывод

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

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

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

Демонстрационный код [C++]

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

Пример ниже показывает, как использовать массив параметра и спецификаторы ширины и точности.

#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!
         (DWORD_PTR)L"Bob",                                                // %4
         (DWORD_PTR)6, (DWORD_PTR)L"Bill" };                               // %5!*s!
    const DWORD size = 100+1;
    WCHAR buffer[size];


    if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                       pMessage, 
                       0,  // игнорируется
                       0,  // игнорируется
                       (LPWSTR)&buffer, 
                       size, 
                       (va_list*)pArgs))
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
        return;
    }

    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!";

    pBuffer = GetFormattedMessage(pMessage, 4, 2, L"Bill", L"Bob", 6, L"Bill");
    if (pBuffer)
    {
        wprintf(L"Formatted message: %s\n", pBuffer);
        LocalFree(pBuffer);
    }
    else
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
    }
}

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;
}

 

Смотри также

Обзор Обработка ошибок, Функции, используемые при обработке ошибок, Ресурс MESSAGETABLE, Компилятор сообщения, Таблицы сообщений

Размещение и совместимость FormatMessage

К Windows Vista Да
л Windows XP Да
и Windows 2000 Professional Да
е Windows NT Workstation Да версии 3.1
н Windows Me Да
т Windows 98 Да
  Windows 95 Да
С Windows Server 2008  
е Windows Server 2003 Да
р Windows 2000 Server Да
в Windows NT Server Да версии 3.1
е
р
Используемая библиотека Kernel32.lib
Используемая DLL Kernel32.dll
Заголовочный файл
- объявлено в Winbase.h
- включено в Windows.h
Unicode Реализуется как FormatMessageW (Unicode) и FormatMessageA (ANSI)
Замечания по платформе Не имеется

Назад в оглавление
На главную страницу
В оглавление справки

Hosted by uCoz