Jump to content

GetTextMetrics + GetTextFace


Mat
 Share

Recommended Posts

Sorry for the very untidy code, but it appears no-ones done this before on the forums, and I needed this :huggles:

The idea is a small tool that tells you all about the font of a control. I needed this for GUIHotkey.au3 to find out what the system defaults were for a hotkey control, and I thought it could be useful in other places too.

The tool? "What font is That?". You will need my GUIFinder.au3 (or just look at the code and point out the obvious error that is bound to be in there somewhere...)

#include <WinApi.au3>
#include <GUIFinder.au3>

; What font is that?

Global Const $tagTEXTMETRIC = "long tmHeight;long tmAscent;long tmDescent;long tmInternalLeading;long tmExternalLeading;" & _
        "long tmAveCharWidth;long tmMaxCharWidth;long tmWeight;long tmOverhang;long tmDigitizedAspectX;long tmDigitizedAspectY;" & _
        "wchar tmFirstChar;wchar tmLastChar;wchar tmDefaultChar;wchar tmBreakChar;byte tmItalic;byte tmUnderlined;byte tmStruckOut;" & _
        "byte tmPitchAndFamily;byte tmCharSet"

Opt("GUIOnEventMode", 1)

Global $hGUI, $hFinder, $hList

_Main()

While 1
    Sleep(100)
WEnd

Func _Main()
    $hGUI = GUICreate("What Font is that?", 300, 400)
    GUISetOnEvent(-3, "_Exit")
    $hFinder = GUICtrlCreateFinder(2, 400 / 2 - 16)
    GUICtrlSetOnEvent(-1, "_FinderOpen")
    $hList = GUICtrlCreateEdit("", 36, 2, 300 - 38, 396)
    GUICtrlCreateLabel("A", 2, 2, 30, 30)
    GUICtrlSetFont(-1, 14, 200, 2, "Times New Roman")
    GUISetState()
EndFunc   ;==>_Main

Func _GetTextFace($hDC)
    Local $aRet, $nCount, $tBuffer, $pBuffer
    $aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0)
    $nCount = $aRet[0]
    $tBuffer = DllStructCreate("wchar[" & $aRet[0] & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $nCount, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, 0)
    Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_GetTextFace

Func _GetTextMetrics($hDC)
    Local $aRet, $tBuffer, $pBuffer
    $tBuffer = DllStructCreate($tagTEXTMETRIC)
    $pBuffer = DllStructGetPtr($tBuffer)
    DllCall("Gdi32.dll", "bool", "GetTextMetricsW", "handle", $hDC, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, 0)
    Return $tBuffer
EndFunc   ;==>_GetTextMetrics

Func _FinderOpen()
    Local $sString, $hDC
    $hCur = $FINDER_HWND
    $hDC = _WinAPI_GetDC($hCur)
    $tText = _GetTextMetrics($hDC)
    $sString = "** Simple **" & @CRLF
    $sString &= "Face: " & @TAB & @TAB & _GetTextFace($hDC) & @CRLF
    $sString &= "Size: " & @TAB & @TAB & _WinAPI_MulDiv(DllStructGetData($tText, "tmHeight"), 72, _WinAPI_GetDeviceCaps($hDC, 90)) & @CRLF
    $sString &= "Italic: " & @TAB & @TAB & (DllStructGetData($tText, "tmItalic") <> 0) & @CRLF
    $sString &= "Underlined: " & @TAB & (DllStructGetData($tText, "tmUnderlined") <> 0) & @CRLF
    $sString &= "Struck Out: " & @TAB & (DllStructGetData($tText, "tmStruckOut") <> 0) & @CRLF
    $sString &= "Weight: " & @TAB & @TAB & DllStructGetData($tText, "tmWeight") & @CRLF
    $sString &= @CRLF & "** Advanced **" & @CRLF
    $sString &= "Height: " & @TAB & @TAB & DllStructGetData($tText, "tmHeight") & @CRLF
    $sString &= "Ascent: " & @TAB & @TAB & DllStructGetData($tText, "tmAscent") & @CRLF
    $sString &= "Descent: " & @TAB & @TAB & DllStructGetData($tText, "tmDescent") & @CRLF
    $sString &= "Internal Leading: " & @TAB & DllStructGetData($tText, "tmInternalLeading") & @CRLF
    $sString &= "External Leading: " & @TAB & DllStructGetData($tText, "tmExternalLeading") & @CRLF
    $sString &= "Ave Char Width: " & @TAB & DllStructGetData($tText, "tmAveCharWidth") & @CRLF
    $sString &= "Max Char Width: " & @TAB & DllStructGetData($tText, "tmMaxCharWidth") & @CRLF
    $sString &= "Overhang: " & @TAB & DllStructGetData($tText, "tmOverhang") & @CRLF
    $sString &= "Digitized AspectX: " & @TAB & DllStructGetData($tText, "tmDigitizedAspectX") & @CRLF
    $sString &= "Digitized AspectY: " & @TAB & DllStructGetData($tText, "tmDigitizedAspectY") & @CRLF
    $sString &= "First Char: " & @TAB & DllStructGetData($tText, "tmFirstChar") & @CRLF
    $sString &= "Last Char: " & @TAB & DllStructGetData($tText, "tmLastChar") & @CRLF
    $sString &= "Default Char: " & @TAB & DllStructGetData($tText, "tmDefaultChar") & @CRLF
    $sString &= "Break Char: " & @TAB & DllStructGetData($tText, "tmBreakChar") & @CRLF
    $sString &= "Pitch And Family: " & @TAB & DllStructGetData($tText, "tmPitchAndFamily") & @CRLF
    $sString &= "Char Set: " & @TAB & @TAB & DllStructGetData($tText, "tmCharSet") & @CRLF
    GUICtrlSetData($hList, $sString, "")
    _WinAPI_ReleaseDC($hCur, $hDC)
EndFunc   ;==>_FinderOpen

Func _Exit()
    Exit
EndFunc   ;==>_Exit

I added a label with a different font to test on. No matter what you drag it onto it returns the same:

** Simple **
Face:       System
Size:       12
Italic:         False
Underlined:     False
Struck Out:     False
Weight:         700

** Advanced **
Height:         16
Ascent:         13
Descent:        3
Internal Leading:   3
External Leading:   0
Ave Char Width:     7
Max Char Width:     14
Overhang:   0
Digitized AspectX:  96
Digitized AspectY:  96
First Char:      
Last Char:  ™
Default Char:   €
Break Char:      
Pitch And Family:   33
Char Set:       0

Oh yes and:

GetTextFace

GetTextMetrics

TextMetric structure

Thanks for any help... It's killing me here :D

Link to comment
Share on other sites

Thats 24 hours, and i'm fairly sure someone can help...

I'm fairly sure that my main problem is that I'm using the functions wrong, This is probably the closest thing I can get to a possible error...

To determine whether a font is a TrueType font, first select it into a DC, then call GetTextMetrics, and then check for TMPF_TRUETYPE in TEXTMETRIC.tmPitchAndFamily. Note that GetDC returns an uninitialized DC, which has "System" (a bitmap font) as the default font; thus the need to select a font into the DC.

I can make absolutely no sense from that statement, and I have never had to "select" a font into a DC. But at least that would explain why it consistantly returned the system standard.

Mat

Edit: More info:

The GetDC function retrieves a common, class, or private DC depending on the class style of the specified window. For class and private DCs, GetDC leaves the previously assigned attributes unchanged. However, for common DCs, GetDC assigns default attributes to the DC each time it is retrieved. For example, the default font is System, which is a bitmap font. Because of this, the handle to a common DC returned by GetDC does not tell you what font, color, or brush was used when the window was drawn. To determine the font, call GetTextFace.

But I was :D

Edited by Mat
Link to comment
Share on other sites

Fixed, and please note the demo doesn't require chasing down a custom UDF:

#include <GuiConstantsEx.au3>
#include <WinApi.au3>

Global Const $tagTEXTMETRIC = "long tmHeight;long tmAscent;long tmDescent;long tmInternalLeading;long tmExternalLeading;" & _
        "long tmAveCharWidth;long tmMaxCharWidth;long tmWeight;long tmOverhang;long tmDigitizedAspectX;long tmDigitizedAspectY;" & _
        "wchar tmFirstChar;wchar tmLastChar;wchar tmDefaultChar;wchar tmBreakChar;byte tmItalic;byte tmUnderlined;byte tmStruckOut;" & _
        "byte tmPitchAndFamily;byte tmCharSet"

Opt("GUIOnEventMode", 1)

Global $hGUI, $hList

_Main()

Func _Main()
    $hGUI = GUICreate("What Font is that?", 340, 550)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    GUICtrlCreateButton("Get My Font", 100, 20, 140, 50)
    GUICtrlSetOnEvent(-1, "_FinderOpen")
    GUICtrlSetFont(-1, 14, 200, 2, "Times New Roman")
    GUICtrlCreateButton("Get My Font", 100, 90, 140, 50)
    GUICtrlSetOnEvent(-1, "_FinderOpen")
    GUICtrlSetFont(-1, 16, 300, 2, "Tahoma")

    $hList = GUICtrlCreateEdit("", 20, 160, 300, 370)
    GUISetState()

    While 1
        Sleep(10)
    WEnd
EndFunc   ;==>_Main

Func _FinderOpen()
    Local $sString = ""
    Local $hCur = @GUI_CtrlHandle
    Local $hDC = _WinAPI_GetDC($hCur)
    Local $hFont = _SendMessage($hCur, 0x0031) ; $WM_GETFONT
    Local $oFont = _WinAPI_SelectObject($hDC, $hFont)
    Local $tText = _GetTextMetrics($hDC)
    $sString = "** Simple **" & @CRLF
    $sString &= "Face: " & @TAB & @TAB & _GetTextFace($hDC) & @CRLF
    $sString &= "Size: " & @TAB & @TAB & _WinAPI_MulDiv(DllStructGetData($tText, "tmHeight"), 72, _WinAPI_GetDeviceCaps($hDC, 90)) & @CRLF
    $sString &= "Italic: " & @TAB & @TAB & (DllStructGetData($tText, "tmItalic") <> 0) & @CRLF
    $sString &= "Underlined: " & @TAB & (DllStructGetData($tText, "tmUnderlined") <> 0) & @CRLF
    $sString &= "Struck Out: " & @TAB & (DllStructGetData($tText, "tmStruckOut") <> 0) & @CRLF
    $sString &= "Weight: " & @TAB & @TAB & DllStructGetData($tText, "tmWeight") & @CRLF
    $sString &= @CRLF & "** Advanced **" & @CRLF
    $sString &= "Height: " & @TAB & @TAB & DllStructGetData($tText, "tmHeight") & @CRLF
    $sString &= "Ascent: " & @TAB & @TAB & DllStructGetData($tText, "tmAscent") & @CRLF
    $sString &= "Descent: " & @TAB & @TAB & DllStructGetData($tText, "tmDescent") & @CRLF
    $sString &= "Internal Leading: " & @TAB & DllStructGetData($tText, "tmInternalLeading") & @CRLF
    $sString &= "External Leading: " & @TAB & DllStructGetData($tText, "tmExternalLeading") & @CRLF
    $sString &= "Ave Char Width: " & @TAB & DllStructGetData($tText, "tmAveCharWidth") & @CRLF
    $sString &= "Max Char Width: " & @TAB & DllStructGetData($tText, "tmMaxCharWidth") & @CRLF
    $sString &= "Overhang: " & @TAB & DllStructGetData($tText, "tmOverhang") & @CRLF
    $sString &= "Digitized AspectX: " & @TAB & DllStructGetData($tText, "tmDigitizedAspectX") & @CRLF
    $sString &= "Digitized AspectY: " & @TAB & DllStructGetData($tText, "tmDigitizedAspectY") & @CRLF
    $sString &= "First Char: " & @TAB & DllStructGetData($tText, "tmFirstChar") & @CRLF
    $sString &= "Last Char: " & @TAB & DllStructGetData($tText, "tmLastChar") & @CRLF
    $sString &= "Default Char: " & @TAB & DllStructGetData($tText, "tmDefaultChar") & @CRLF
    $sString &= "Break Char: " & @TAB & DllStructGetData($tText, "tmBreakChar") & @CRLF
    $sString &= "Pitch And Family: " & @TAB & DllStructGetData($tText, "tmPitchAndFamily") & @CRLF
    $sString &= "Char Set: " & @TAB & @TAB & DllStructGetData($tText, "tmCharSet") & @CRLF
    GUICtrlSetData($hList, $sString, "")
    _WinAPI_ReleaseDC($hCur, $hDC)
EndFunc   ;==>_FinderOpen

Func _GetTextMetrics($hDC)
    Local $aRet, $tBuffer, $pBuffer
    $tBuffer = DllStructCreate($tagTEXTMETRIC)
    $pBuffer = DllStructGetPtr($tBuffer)
    DllCall("Gdi32.dll", "bool", "GetTextMetricsW", "handle", $hDC, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, 0)
    Return $tBuffer
EndFunc   ;==>_GetTextMetrics

Func _GetTextFace($hDC)
    Local $aRet, $nCount, $tBuffer, $pBuffer
    $aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0)
    $nCount = $aRet[0]
    $tBuffer = DllStructCreate("wchar[" & $aRet[0] & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $nCount, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, 0)
    Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_GetTextFace

Func _Exit()
    Exit
EndFunc   ;==>_Exit

This was related to this topic: _WINAPI_GetTextExtent32: how to use so result is correct for different font sizes

Melba23 pointed out the need to get a handle to the font and set it for DC. The critical change is here:

Func _FinderOpen()
    Local $sString = ""
    Local $hCur = @GUI_CtrlHandle
    Local $hDC = _WinAPI_GetDC($hCur)
    Local $hFont = _SendMessage($hCur, 0x0031) ; $WM_GETFONT
    Local $oFont = _WinAPI_SelectObject($hDC, $hFont)
    Local $tText = _GetTextMetrics($hDC)
    
    ; ...
    
EndFunc ; ==>_FinderOpen

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Edit: And whats wrong with chasing down a custom UDF? It looks so much nicer with the finder :huggles:

You sounded interested in why you might not have gotten any answers before this. Posting an incomplete demo that requires extra effort to use certainly reduces people's interest in tracking down the problem.

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

You sounded interested in why you might not have gotten any answers before this. Posting an incomplete demo that requires extra effort to use certainly reduces people's interest in tracking down the problem.

:D

hmmm... I suppose, but then I also wanted to test a wide range of object too, nevertheless, this will be the second lesson you have taught me today :huggles: I just hope I am a dedicated pupil.

Mat

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...