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 參數會指定要配置給輸出訊息緩衝區的最小 TCHA 數目。 呼叫端應該使用 LocalFree 函式,在不再需要緩衝區時釋出緩衝區。

如果格式化訊息的長度超過 128K 個字節,則 FormatMessage 將會失敗,且 後續呼叫 GetLastError 會傳回 ERROR_MORE_DATA

在舊版 Windows 中,編譯 Windows 市集應用程式時無法使用此值。 從 Windows 10,可以使用此值。

Windows Server 2003 和 Windows XP:

如果格式化訊息的長度超過 128K 個字節, 則 FormatMessage 將不會自動失敗,並出現 錯誤ERROR_MORE_DATA

FORMAT_MESSAGE_ARGUMENT_ARRAY
0x00002000
Arguments 參數不是va_list結構,而是代表自變數之值的陣列指標。

此旗標不能與64位整數值搭配使用。 如果您使用 64 位整數,則必須使用 va_list 結構。

FORMAT_MESSAGE_FROM_HMODULE
0x00000800
lpSource 參數是模組句柄,其中包含要搜尋的訊息表資源 (s) 。 如果這個 lpSource 句柄為 NULL,則會搜尋目前進程的應用程式圖像檔。 此旗標不能與 FORMAT_MESSAGE_FROM_STRING搭配使用。

如果模組沒有消息表資源,函式會失敗並 ERROR_RESOURCE_TYPE_NOT_FOUND

FORMAT_MESSAGE_FROM_STRING
0x00000400
lpSource 參數是包含訊息定義的 Null 終止字串指標。 訊息定義可能包含插入序列,就像消息表資源中的訊息文字一樣。 此旗標不能與 FORMAT_MESSAGE_FROM_HMODULEFORMAT_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的非零值,它會指定輸出行中的字元數上限。 函式會忽略訊息定義文字中的一般換行符。 函式絕不會分割以空格符分隔的字串。 函式會將硬式編碼換行符儲存在訊息定義文字中,並儲存到輸出緩衝區中。 硬式編碼換行符元會以 %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 中指定的位址處。

這個緩衝區不能大於64K個字節。

[in] nSize

如果未設定 FORMAT_MESSAGE_ALLOCATE_BUFFER 旗標,此參數會在 TCHAR 中指定輸出緩衝區的大小。 如果 已設定FORMAT_MESSAGE_ALLOCATE_BUFFER ,此參數會指定要配置給輸出緩衝區的 最小 TCHA 數目

輸出緩衝區不能大於 64K 個字節。

[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

備註

在消息正文中,動態格式化訊息支持數個逸出序列。 這些逸出序列及其意義會顯示在下表中。 所有逸出序列的開頭為百分比字元 (%) 。

逸出序列 意義
%0 終止消息正文行,而不使用尾端的新行字元。 這個逸出序列可用來建置長行或終止訊息本身,而不需尾端的新行字元。 對於提示訊息很有用。
%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、Bill、Bob、6、Bill (,如果使用 FORMAT_MESSAGE_ARGUMENT_ARRAY 旗標) 。 格式化字串接著會是 「Bi Bob Bill」。。

當來源字串包含寬度和精確度規範時,重複插入數位可能不會產生預期的結果。 如果您以 %1 取代 %5,函式會嘗試在位址 6 列印字串, (可能導致存取違規) 。

不支援浮點格式規範 e、E、f 和 g。 因應措施是使用 StringCchPrintf 函 式,將浮點數格式化為暫存緩衝區,然後使用該緩衝區作為插入字串。

使用 I64 前置詞的插入會被視為兩個 32 位自變數。 在使用後續自變數之前,必須先使用這些自變數。 請注意,使用 StringCchPrintf 而不是這個前置詞可能會比較容易。

 

在百分比字元之後的任何其他非digit 字元,會格式化在輸出訊息中,而不需要百分比字元。 以下有一些範例。

格式字串 產生的輸出
%% 單一百分比符號。
%B 單一空間。 此格式字串可用來確保消息正文行中適當的尾端空格數目。
%. 單一句號。 這個格式字串可以用來在行開頭包含單一句號,而不終止訊息文字定義。
%! 單一驚嘆號。 這個格式字串可以用來在插入之後立即包含驚嘆號,而不會誤用格式字串的開頭。
%n 當格式字串發生在行尾時,即為硬換行符。 當 FormatMessage 提供一般換行符,讓訊息符合特定寬度時,此格式字串會很有用。
%r 沒有尾端換行符的硬式歸位字元。
%t 單一索引標籤。
 

安全性備註

如果沒有 FORMAT_MESSAGE_IGNORE_INSERTS呼叫此函式, Arguments 參數必須包含足夠的參數,才能滿足訊息字串中的所有插入序列,而且它們必須是正確的類型。 因此,請勿在啟用插入時使用不受信任或未知的訊息字串,因為它們可以包含比 Arguments 提供的更多插入序列,或可能屬於錯誤類型的插入序列。 特別是,不需FORMAT_MESSAGE_IGNORE_INSERTS,即可取得從 API 傳回的任意系統錯誤碼,並使用FORMAT_MESSAGE_FROM_SYSTEM

範例

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
標頭 winbase.h (包含 Windows.h)
程式庫 Kernel32.lib
DLL Kernel32.dll

另請參閱

錯誤處理函式

訊息編譯程式

訊息數據表