在 CTextDialog::GetOutline() 中呼叫 GetGlyphOutline,SelectObject 字體後失敗,疑似 DC 權限問題。
// 錯誤:按鈕 DC 可能無字體支援、裁剪區異常
CWnd* pWnd = GetDlgItem(IDC_BUTTON);
CDC* pDC = pWnd->GetDC(); // 不穩定
// 正確:建立記憶體 DC,相容螢幕
CClientDC screenDC(this); // 或 CWindowDC
CDC memDC;
memDC.CreateCompatibleDC(&screenDC);
LOGFONT lf = {0};
_tcscpy_s(lf.lfFaceName, _T("微軟正黑體")); // 字體名稱
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfHeight = -MulDiv(18, screenDC.GetDeviceCaps(LOGPIXELSY), 72); // 18 pt
CFont font;
font.CreateFontIndirect(&lf);
CFont* pOldFont = memDC.SelectObject(&font); // 必須選入 DC
// 此時 memDC 擁有正確字體,可呼叫 GetGlyphOutline
// ...
memDC.SelectObject(pOldFont); // 恢復
GLYPHMETRICS gm = {0};
MAT2 mat2 = {{0,1},{0,0},{0,0},{0,1}}; // 單位矩陣
DWORD size = GetGlyphOutline(memDC.m_hDC, 'A', GGO_NATIVE, &gm, 0, NULL, &mat2);
if (size == GDI_ERROR) { /* 處理錯誤 */ }
std::vector buffer(size);
GetGlyphOutline(memDC.m_hDC, 'A', GGO_NATIVE, &gm, size, buffer.data(), &mat2);
// buffer 即為輪廓資料 (TTPOLYGONHEADER 串列)
void CTextDialog::GetOutline() {
CClientDC screenDC(this);
CDC memDC;
memDC.CreateCompatibleDC(&screenDC);
LOGFONT lf = {0};
_tcscpy_s(lf.lfFaceName, _T("微軟正黑體"));
lf.lfHeight = -MulDiv(18, screenDC.GetDeviceCaps(LOGPIXELSY), 72);
CFont font;
font.CreateFontIndirect(&lf);
CFont* pOldFont = memDC.SelectObject(&font);
// 取得字形 '中' 的輪廓
GLYPHMETRICS gm = {0};
MAT2 mat2 = {{0,1},{0,0},{0,0},{0,1}};
DWORD size = GetGlyphOutline(memDC.m_hDC, _T('中'), GGO_NATIVE, &gm, 0, NULL, &mat2);
if (size != GDI_ERROR) {
std::vector buf(size);
GetGlyphOutline(memDC.m_hDC, _T('中'), GGO_NATIVE, &gm, size, buf.data(), &mat2);
// 解析 TTPOLYGONHEADER -> TTPOLYCURVE -> 點座標...
}
memDC.SelectObject(pOldFont);
}
| 問題 | 解決 |
|---|---|
| GetGlyphOutline 回傳 GDI_ERROR | 字體未正確選入 DC、字元不在字體表、DC 不支援 |
| 輪廓座標偏移 | gm.gmCellIncX, gm.gmBlackBoxX/Y 為進位寬高,需配合 gm.gmptGlyphOrigin 計算實際座標 |
| 中文字形無輪廓 | 確認字體支援該字元 (如「微軟正黑體」支援常用中文) |
GetGlyphOutline 需要**有效的 HDC 且已選入目標字體**。請使用 CClientDC + CreateCompatibleDC 建立記憶體 DC,建立 CFont 並 SelectObject 後再呼叫。按鈕控制項 DC 不穩定,不可用於字形查詢。