首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows 下以 TrueType 字型繪製中文:MultiByteToWideChar 與 TextOutW 實戰

     編輯:VC 教學

前言

早期開發者常嘗試自行解析 TrueType 字型檔(.ttf)繪製中文,但 Apple 持有 TrueType hinting 專利,FreeType 專案曾面臨法律風險。事實上,Windows 95/NT 內建完整的 Unicode 文字輸出支援,只需將多位元組字串(ANSI/CP936)轉為 Unicode(UTF-16),再呼叫 TextOutW 即可正確繪製中文,無需自行解析字型檔。

核心代碼範例

BOOL bResult = m_Font.CreateFont(
    -16, 0, 0, 0, 400, 0, 0, 0,
    134,           // CHARSET: GB2312 (簡體中文)
    3, 2, 1, 50,
    "SimSun"       // 字型名稱:新細明體/宋體
);

char *pText = "Test中文顯示測試Test";
wchar_t wBuffer[256];

// 1. 多位元組轉 Unicode(代碼頁 936 = GB2312)
int nLength = MultiByteToWideChar(
    936,                // Code Page: GB2312
    MB_PRECOMPOSED,     // 合成字元旗標
    pText, -1,          // 來源字串,-1 表以 null 結尾
    wBuffer, 256        // 目標緩衝區
);

CDC *pDC = GetDC();
CFont *pFontTemp = (CFont *)pDC->SelectObject(&m_Font);

// 2. 必須呼叫 TextOutW(寬字元版),不可用 dc.TextOut()
TextOutW(pDC->m_hDC, 80, 80, wBuffer, nLength - 1); // -1 排除結尾 null

pDC->SelectObject(pFontTemp);
ReleaseDC(pDC);

關鍵技術點深度解析

為什麼要用代碼頁 936?

簡體中文 Windows 內定代碼頁為 936(GB2312)。MultiByteToWideChar 的第一個參數必須指定正確代碼頁,才能正確將「中文 ANSI 字串」轉為 Unicode。繁體中文環境則使用 950(Big5)。

TextOutW vs dc.TextOut()

  • dc.TextOut() 是 MFC 封裝,內部呼叫 TextOutA(ANSI 版),會依專案字元集設定再轉換一次,導致雙重轉換錯誤。
  • TextOutW 直接接收 wchar_t*,繞過 ANSI 層,確保 Unicode 字形正確送達 GDI。

代碼頁 936 的系統相依性

早期 Windows 95/98 若未安裝簡體中文支援,系統可能缺少 cp_936.nls。解決方法:

  1. 從 VC++ 安裝目錄複製 cp_936.nls 至 Windows\System。
  2. 登錄表 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Nls\CodePage 新增 936 = "cp_936.nls"。
  3. 登錄表 ...\Nls\Locale 新增 00000804 = "Chinese(PRC)"。

現代 Windows(XP 以上)預設已內建,無需手動設定。

字型建立參數說明

參數值說明
高度-16負值表字元高度(含內部間距),單位邏輯單位
CharSet134GB2312_CHARSET,指定字型字符集
OutPrecision3OUT_TT_PRECIS,優先使用 TrueType 字型
ClipPrecision2CLIP_DEFAULT_PRECIS
Quality1DEFAULT_QUALITY
PitchAndFamily50DEFAULT_PITCH | FF_DONTCARE

常見問題與解決方案

現象原因解決
中文顯示為方框/亂碼字型不支援中文或 CharSet 錯誤確認字型含中文字形,CharSet=134(簡體)/136(繁體)
英文正常、中文消失用 TextOutA 而非 TextOutW強制呼叫 TextOutW,傳入 wchar_t 緩衝區
MultiByteToWideChar 回傳 0代碼頁未安裝或字串含無效序列檢查 cp_936.nls,改用 MB_ERR_INVALID_FLAGS 除錯

現代最佳實踐(Unicode 專案)

若專案設定為「使用 Unicode 字元集」(VC++ 2005 以降預設),CString、TCHAR 皆為 wchar_t,可直接使用:

CString str = _T("Test中文測試");
pDC->TextOut(80, 80, str); // 自動呼叫 TextOutW

無需手動 MultiByteToWideChar,編譯器自動處理字面常數與字串轉換。

掌握 MultiByteToWideChar + TextOutW 的經典組合,不僅能解決舊專案相容性問題,更能深入理解 Windows 文字輸出管線的核心運作機制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved