PC的文字遊戲一般在設定界面中有選擇字型的地方,一般來說是從系統字型中篩選出合适的字型,很少會給玩家字型對話框來選擇的。這個篩選是靠EnumFontFamilies。
int EnumFontFamilies(
HDC hdc, // handle to device control
LPCTSTR lpszFamily, // pointer to family-name string
FONTENUMPROC lpEnumFontFamProc, // pointer to callback function
LPARAM lParam // address of application-supplied data
);
裡面主要的參數是FONTENUMPROC lpEnumFontFamProc,定義如下:
int CALLBACK EnumFontFamProc(
ENUMLOGFONT FAR *lpelf, // pointer to logical-font data
NEWTEXTMETRIC FAR *lpntm, // pointer to physical-font data
int FontType, // type of font
LPARAM lParam // address of application-defined data
);
第一個參數指向ENUMLOGFONT資料,
typedef struct tagENUMLOGFONT { // elf
LOGFONT elfLogFont;
BCHAR elfFullName[LF_FULLFACESIZE];
BCHAR elfStyle[LF_FACESIZE];
} ENUMLOGFONT;
其實也就是一個LOGFONT + 字型名,是以調試的時候可以在記憶體跟随這個結構來看字型名。
LOGFONT應該很熟了,如下:
typedef struct tagLOGFONT { // lf
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight; // 10
BYTE lfItalic; // 14
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet; // 17 一般判斷這裡
BYTE lfOutPrecision; // 18
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE]; // 1c
} LOGFONT;
第二個指向 NEWTEXTMETRIC,結構如下:
typedef struct tagNEWTEXTMETRIC { // ntm
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
BCHAR tmFirstChar;
BCHAR tmLastChar;
BCHAR tmDefaultChar;
BCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
DWORD ntmFlags;
UINT ntmSizeEM;
UINT ntmCellHeight;
UINT ntmAvgWidth;
} NEWTEXTMETRIC;
字段很多,不一一介紹了。
第三個參數FontType隻有3個值:
DEVICE_FONTTYPE 1
RASTER_FONTTYPE 2
TRUETYPE_FONTTYPE 4 一般選這個
最後一個參數LPARAM lParam其實就是EnumFontFamilies中第4個參數,可以傳點使用者自定義資料。
下面是一個執行個體。
00450700 /. 55 push ebp ; EnumFontFamilies_Callback
00450701 |. 8BEC mov ebp, esp
00450703 |. F645 10 04 test byte ptr [ebp+10], 4 // 這裡看FontType是不是TRUETYPE_FONTTYPE
00450707 |. 8B45 08 mov eax, dword ptr [ebp+8] // eax = lpelf
0045070A |. 75 07 jnz short 00450713
0045070C |. B8 01000000 mov eax, 1
00450711 |. EB 4A jmp short 0045075D
00450713 |> 8A50 17 mov dl, byte ptr [eax+17] // [eax + 17] is lpelf->lfCharSet
00450716 |. 80FA 80 cmp dl, 80 // Charset -> 86 80是SJIS,改成86簡體,88繁體
00450719 |. 74 07 je short 00450722
0045071B |. B8 01000000 mov eax, 1
00450720 |. EB 3B jmp short 0045075D
00450722 |> 33D2 xor edx, edx
00450724 |. 8A50 1B mov dl, byte ptr [eax+1B]
00450727 |. 83E2 03 and edx, 3
0045072A |. 4A dec edx
0045072B |. 74 07 je short 00450734
0045072D |. B8 01000000 mov eax, 1
00450732 |. EB 29 jmp short 0045075D
00450734 |> 0FBE50 1C movsx edx, byte ptr [eax+1C]
00450738 |. 83FA 40 cmp edx, 40
0045073B |. 75 07 jnz short 00450744
0045073D |. B8 01000000 mov eax, 1
00450742 |. EB 19 jmp short 0045075D
00450744 |> 83C0 1C add eax, 1C
00450747 |. 50 push eax ; /lParam
00450748 |. 6A 00 push 0 ; |wParam = 0
0045074A |. 68 43010000 push 143 ; |Message = CB_ADDSTRING
0045074F |. 8B55 14 mov edx, dword ptr [ebp+14] ; |
00450752 |. 52 push edx ; |hWnd
00450753 |. E8 C8741900 call <jmp.&USER32.SendMessageA> ; /SendMessageA
00450758 |. B8 01000000 mov eax, 1 // 這裡向ComboBox添加項目
0045075D |> 5D pop ebp
0045075E /. C2 1000 retn 10