Hello guys, i have been looking lately at EnumFonts, as i need to list all fonts installed on the system.
So far i have been unsuccessfull, can some please some shed some light on it or perhaps an example.
Thnakyou
I just seen a post by Donkey (http://www.masm32.com/board/index.php?topic=10327.msg75617#msg75617") where
he claims to have something doing the same on his site!
---
Will
The example is for a font menu, the actual snippet for enumerating fonts is this....
// load the LOGFONT structure to pass info to the enumeration API
mov B[lf.lfCharSet],ANSI_CHARSET
mov B[lf.lfFaceName],0
mov B[lf.lfPitchAndFamily],0
// We need a device context in order to enumerate fonts, any screen window will do (or printer DC if you want printer fonts)
invoke GetDlgItem,[hDlg],1001
mov esi,eax
invoke GetDC,esi
mov ebx,eax
invoke EnumFontFamiliesExA,ebx,ADDR lf,OFFSET EnumFontFamExProc,[SubMenuHandle],0
// release the device context
invoke ReleaseDC,esi,ebx
EnumFontFamExProc FRAME lpelfe,lpntme,FontType,lParam
uses ebx
// The font data is passed in a ENUMLOGFONTEX struct at address lpelfe
// you can get the font name from that structure in ENUMLOGFONTEX.LOGFONT.lfFaceName
// Or alternatively you can use the full font name in ENUMLOGFONTEX.elfFullName
// Note that ENUMLOGFONTEX.elfFullName doesn't provide the same data on 9x and NT based systems
mov ebx,[lpelfe]
add ebx,ENUMLOGFONTEX.elfFullName
// EBX points to the full font name
... Do what you want to with the font name here
// continue the enumeration until all fonts are processed
mov eax,TRUE
RET
ENDF
just a related question. . .
suppose i want to display info on fonts that are not in the font table but like in a folder, what would i do ?
successively load each font into the font table, get the info i want.. then unload it ? or is there some other way ?
- - - - - - - - - - -
Also, suppose i supply a typeface name in the LOGFONT structure, but that font wasn't found..would the function return some other font that matched the criteria most closely ? - and if it did.. would it alert me to the fact that it is not the typeface name i asked for .
thanks!
Since the API really only allows you to get information about a font with reference to the device context and handle of the font, it must be added to the font table before you can examine it. Windows allows an application to add a font (for its use only if you like) and remove it, you can add the font using AddFontResource (http://msdn.microsoft.com/en-us/library/ms534231(VS.85).aspx) enumerate it then remove it using RemoveFontResource. Alternatively you can examine the file directly by writing a parser to read the TTF file format (http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html) (if you are working with true type fonts) which is very similar to RIFF files in structure.
thanks for the advice & the useful link :thumbu
i kinda took this from your post donkey and made an example out of it, Very simple thingy. Thanks for the help donkey. It was something i dodnt know how to do.
Hey... i was trying to upgrade the enumfonts thingy to show the actually font draw within the listbox but things aren't working yet. I'm just processing ODA_DRAWENTIRE at the moment. I don't know if there's something wrong with the ENUMLOGFONTEX pointer. Can someone check this out? Thanks
your attachment has no enumeration code
it makes a nice window, is all :bg
i did notice the absence of
WndProc PROC uses edi hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
Sorry. I'm not sure what you mean but i'm devastated. Thanks
in WndProc, you use EDI without preserving it
yeah.... i tried uses edi esi and doesn't work wither.
well - that is A problem - not the only problem
in the EnumFontFamExProc callback function, you are not accessing the LOGFONT structure members
it says you can cast it as a ENUMLOGFONTEX struc, but that over-complicates things if you do not need the metrics
just cast it as a LOGFONT to access the members
if you do want the metrics, to access members of the LOGFONT part of the ENUMLOGFONTEX struc, use...
assume esi:PTR ENUMLOGFONTEX
mov eax,dword ptr [esi].elfLogFont.lfFaceName
to get the first 4 letters of the name of the font, for example
the LOGFONT struc is a sub-member of the ENUMLOGFONTEX struc
it is named elfLogFont
Damn i get register value overwritten by invoke. Any ideas on what this means? Can fix it.
it probably means that you ran out of registers by using ADDR
show me the invoke line :bg
i see another little issue
you are filling the list during WM_CREATE, then sending strings to it
the window hasn't been created, yet
not sure, but i think that thing will enumerate fonts all day long
it will list each font, size, pitch/family until it goes through all of them :P
;assemble as a GUI app
include \masm32\include\masm32rt.inc
.data
lf LOGFONT <>
cf CHOOSEFONT <>
.code
start: mov cf.lStructSize,sizeof CHOOSEFONT
mov cf.rgbColors,NULL
mov cf.hwndOwner,NULL
mov cf.lpLogFont,offset lf
mov cf.Flags,CF_SCREENFONTS or CF_EFFECTS
INVOKE ChooseFont,offset cf
exit
end start
:P
Oh yeah.... that might be the issue. Thanks
invoke Line:
mov eax,dword ptr [esi].elfLogFont.lfFaceName
invoke DrawText,[edi].hdc,eax,-1,[edi].rcItem,DT_LEFT
also - you want an address in EAX
change this
mov eax,dword ptr [esi].elfLogFont.lfFaceName
to this
lea eax,[esi].elfLogFont.lfFaceName
and - [edi].rcItem - it wants a pointer to a RECT struc
i have enumerated sizes of a single font
it is much simpler than enumerting all the fonts
in the callback, i just put the info i wanted into a buffer, then display it all after enumeration is done
here is the invoke
INVOKE GetDC,NULL
mov hDc,eax
mov dword ptr LogFnt.lfFaceName,6D726554h ;'Term'
mov dword ptr LogFnt.lfFaceName+4,6C616E69h ;'inal'
mov byte ptr LogFnt.lfFaceName+8,0
mov byte ptr LogFnt.lfCharSet,OEM_CHARSET ;EQU 255
mov byte ptr LogFnt.lfPitchAndFamily,0
INVOKE EnumFontFamiliesEx,hDc,offset LogFnt,EnumFntCB,0,0
and i store the pointer into the buffer in lstPtr...
OPTION PROLOGUE:None
OPTION EPILOGUE:None
EnumFntCB PROC lpLogFont:DWORD,lpMetric:DWORD,fType:DWORD,lParam:DWORD
mov edx,[esp+4]
mov eax,lstPtr
movzx ecx,byte ptr[edx]
mov ch,[edx+4]
mov [eax],ecx
add eax,4
mov lstPtr,eax
ret 16
EnumFntCB ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
after it is done, the buffer contains a list of dwords, one for each size of that font
lstPtr tells me how many are in the list
Thanks but i feel kinda defeated. Moving on to something else.
btw. If im trying to execute code that must be done once outside WM_CREATE like in this case what should i do? Should i send a WM_USER or something. i tried to process WM_CREATE for the listbox but don't know why it doesnt seem to send the message.
easy enough
you can put it in WinMain at the appropriate place
you can create the list in a buffer before the window is created
just make sure you don't over-run your buffer - you are enumerating a lot of stuff :bg
you could put a failsafe in the enumeration callback that skips entries if the buffer is full
then - let WM_PAINT show the text from the buffer
Well.... i guess that all i can say is thanks and i'm looking into it tho it seems kinda hard. I've managed some other hard things before ( for my semi-initiate level ) so i guess i can handle it. latters and thanks
not that bad - i may play with it later if i make good progress on my project
yeah, please do. I kinda tried lots of things and came up with this accoording with your advice. It's kinda clean but the pointers are bad. The font is always the same and lfFaceName too. Thanks
ooops. forgot to attach
I don't use assume myself, but you do:
assume edi:PTR DRAWITEMSTRUCT
assume esi:PTR LOGFONT
once you are done casting the regs, you are supposed to "un assume" them
assume esi:nothing
assume edi:nothing
or bugs will def creep in...
really? i've seen that before but didn't realise what it was about. Could that be important? i'm not using esi/edi on anything else inside WndProc. Thanks Gunner
well - that is important - and i forgot about it, too
but, the last attempt i looked at had some other problems
mainly, the enumerate call was in the message handler and called whenever there was no handled message
that function only needs to be called once, in this case
and, because you are trying to enumerate all fonts, it may take some time
i had a busy day today, so didn't get to play with it
perhaps tomorrow i'll give it a shot :bg
I found this rar (converted to zip just now) file on the net a long while ago (Took some time to find in all my files). It enumerates all the installed fonts and loads up a combobox with the names... You should be able to modify it to draw the font names in the font.
I might even try this :bg
Just looked at this thread, the code snippet at the beginning was part of a demo available on my website to create a font menu, each font on the menu drawn in that font.
Font Menu (http://www.quickersoft.com/donkey/files/FontMenu.zip)
You might find it useful for some ideas.
Edgar
both are good examples, guys :U
yes dave. But you might have missed the face that the enum call is only made if ENUM_FLAG==FALSE. After the enumeration is done i set ENUM_FLAG to TRUE ( or some other value, it's irrelevant cause it only responds to false ), and, so, the call is only made once. Going to check gunner's example. Thanks
Gunner, tho the WM_DRAWITEM processing is not yet fine, the problems i'm dealing with , have to do with pointers. Mainly DRAWITEM.itemID, which is sent with LB_ADDSTRING as an ENUMLOGFONTEX stucture. The Font that is created dispite the itemID changes and the lfFaceName always seems to be the same. Don't know why but as dave would say.... : working on it. Thanks
The best that could be done for now. Nothing wrong with the pointers. Not sure why things go wrong with the listbox. I Could add a scroller if i knew how to process it. Thanks
Go it working with the listbox. It's not ready to process item selection or anything. It only draws items on creation so if you try it out try not to click the items. I noticed that sometimes it crashes so it needs some fixing. Thanks guys
I think that there might be some sort of problem with memory alloc/free because the program errors on exit. does anyone know why? Thanks
could it be that you are missing a call to LocalUnlock ?
no... it has localunlock but maybe it aint working somehow, thanks and bye. working on it
i suggest you double-check
it has LocalAlloc, LocalLock, and LocalFree
i don't see LocalUnlock
now, i am not sure that's the problem
but, it seems to me that the block cannot be freed unless the lock count is 0
easy enough to check
LocalFree should return EAX = 0
Maybe not on the one i posted. Right not on that one. The problem has to do with it. But it seems to work fine with LPTR flag on allocation and neither unlock ( which from what i've read doesn't work with LMEM_FIXED ) nor Freeing.
Final version yet to be released. LOL.
ooops. forgot to attach
New version available. Allows selection tho it does nothing but its cool.
Does anyone know how many times WM_DRAWITEM is called when drawing an item. I was trying to make a window that'd display the alphabet for the selected font, but, when i select an item appears more than one window. The WM_DRAWITEM causes the CreateThread function when ODS_SELEECTED.
hi Donkey, your code will replace font type of all text that the user type on the Editor.
As the result, this can't be used by the user who want to use more than 1 font type in the editor. lol
I think how to modify your code. So, it only change the font type of the Text that User selected.
like the following code. It only do BOLD to the Text that the user selected in the Editor.
.data?
cfm CHARFORMAT2 <>
nLastError DWORD ?
.
.
.
.code
.
.
.
.
mov cfm.cbSize, sizeof cfm
mov cfm.dwMask, (CFM_BOLD or CFM_FACE)
mov cfm.cbSize,60
;GET BOLD STATUS
invoke SendMessage, hEdit1, EM_GETCHARFORMAT, TRUE, ADDR cfm
;TOGGLE BOLD EFFECT
xor cfm.dwEffects, CFE_BOLD
;SET NEW BOLD STATUS
invoke SendMessage, hEdit1, EM_SETCHARFORMAT, SCF_SELECTION, ADDR cfm
.if eax == NULL
invoke GetLastError
mov nLastError,eax
invoke FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,NULL, nLastError, NULL, ADDR szMsgBuff, 128, NULL
invoke MessageBoxEx, NULL, ADDR szMsgBuff, SADD("Error in EM_SETPARAFORMAT"),MB_OK+MB_ICONINFORMATION, LANG_ENGLISH
.endif
xor eax, eax
Hi elmo,
The code was only a demo to show how to enumerate fonts, if I remember correctly I only put in the edit window as an after thought, it was never meant to be a real editor. Feel free to modify it to your needs though.