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