cancel
Showing results for 
Search instead for 
Did you mean: 

GetTextMetrics

Former Member
0 Kudos

Hi everyone...

we want to create new forms in SAP via the SDK. We can add items my oForm.Items.Add() and then set the height of the item (specially for EditText and StaticText).

We want to get the correct height for the items according to the fontsize selected in SAP Business One.

The Support wrote this:

The following is how Business One calculates the Form size in relation

to the font size:

Business One uses 2 windows APIs(GetTextMetrics and

GetTextExtentPoint32) to achieve font size change:

For example:

oldFont = 10, newFont = 12.

Then:

ratio4Height =

GetTextMetrics(Font12).tmHeight/GetTextMetrics(Font10).tmHeight

ratio4Width =

GetTextExtentPoint32(Font12).cx/GetTextExtentPoint32(Font10).cx

But we don't get a value using the GetTextMetrics-API in Microsoft Visual Studio 2005.

Does anyone has an idea how we can use the API correctly?

Best regards,

Manuel Marhold

SoftChip EDV-Systeme

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Hi Manuel,

The solution to reach this is:


'Version 1.0 Kroos Calculating the font height and size of B1

Imports SoftChip.BusinessOneFunctions
Imports System.Runtime.InteropServices

Namespace FontSizeCalculations

    Public Class SCObjectSizeCalculations

        Private _fontHeight As Int32
        Private _fontAverageWidth As Int32

        ''' <summary>
        ''' Get the height of the selected font size of the form
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property GetFontHeight() As Int32
            Get
                Return _fontHeight
            End Get
        End Property

        ''' <summary>
        ''' Get the average font width of the string ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
        ''' </summary>
        ''' <value></value>
        ''' <returns>The average of every character width</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property GetAverageFontWidth() As Int32
            Get
                Return _fontAverageWidth
            End Get
        End Property

        ''' <summary>
        ''' Get the font width of a special string like ABC or something else
        ''' </summary>
        ''' <param name="strString"></param>
        ''' <value></value>
        ''' <returns>The average of every character width</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property GetFontWidth(ByVal strString As String) As Int32
            Get
                Dim _fontWidth As Int32
                _fontWidth = GetFontSizes(strString)
                Return _fontWidth
            End Get
        End Property

        ''' <summary>
        ''' Used for the Windows API
        ''' </summary>
        ''' <remarks></remarks>
        <StructLayout(LayoutKind.Sequential)> Public Structure TEXTMETRIC
            Public tmHeight As Integer
            Public tmAscent As Integer
            Public tmDescent As Integer
            Public tmInternalLeading As Integer
            Public tmExternalLeading As Integer
            Public tmAveCharWidth As Integer
            Public tmMaxCharWidth As Integer
            Public tmWeight As Integer
            Public tmOverhang As Integer
            Public tmDigitizedAspectX As Integer
            Public tmDigitizedAspectY As Integer
            Public tmFirstChar As Char
            Public tmLastChar As Char
            Public tmDefaultChar As Char
            Public tmBreakChar As Char
            Public tmItalic As Byte
            Public tmUnderlined As Byte
            Public tmStruckOut As Byte
            Public tmPitchAndFamily As Byte
            Public tmCharSet As Byte
        End Structure

        ''' <summary>
        ''' Used for the Windows API
        ''' </summary>
        ''' <remarks></remarks>
        <StructLayout(LayoutKind.Sequential)> Structure SIZE
            Public cx As Int32
            Public cy As Int32
        End Structure

        ' Declare Windows API functions
        <DllImport("gdi32")> Shared Function GetTextMetrics(ByVal hdc As Integer, ByRef lpMetrics As TEXTMETRIC) As Integer
            'Nothing in required here
        End Function
        <DllImport("user32")> Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
            'Nothing in required here
        End Function
        <DllImport("user32")> Shared Function GetDC(ByVal hWnd As Integer) As Integer
            'Nothing in required here
        End Function
        <DllImport("user32")> Shared Function ReleaseDC(ByVal hWnd As Integer, ByVal hDC As Integer) As Integer
            'Nothing in required here
        End Function

        <DllImport("gdi32")> Shared Function GetTextExtentPoint32(ByVal hdc As Integer, ByVal lpsz As String, ByVal cbString As Integer, ByRef lpSize As SIZE) As Integer
            'Nothing in required here
        End Function

        ''' <summary>
        ''' Constructor is loading automatically the average width of the font
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            MyBase.New()
            _fontAverageWidth = GetFontSizes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
        End Sub

        ''' <summary>
        ''' Main function to calculate the font width
        ''' </summary>
        ''' <param name="tmp"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function GetFontSizes(ByVal tmp As String) As Int32
            Dim tm As TEXTMETRIC

            Dim mystr As String = SBO_Application.Company.Name & " " & Trim(Mid(SBO_Application.Forms.GetFormByTypeAndCount(169, 1).Items.Item("8").Specific.Caption, InStr(SBO_Application.Forms.GetFormByTypeAndCount(169, 1).Items.Item("8").Specific.Caption, "[")))
            Dim hwnd As Integer = FindWindow(vbNullString, "SAP Business One 2005 A - " & mystr)

            'DC vom Desktop auslesen
            Dim hdc As Integer
            hdc = GetDC(hwnd)

            'Init Windows Font API
            GetTextMetrics(hdc, tm)

            _fontHeight = tm.tmHeight

            'Dim tmp As String
            Dim sz As SIZE

            Dim i As Integer = tmp.Length
            GetTextExtentPoint32(hdc, tmp, i, sz)

            ReleaseDC(hwnd, hdc)
            Return (sz.cx \ tmp.Length)
        End Function

    End Class
End Namespace

Answers (1)

Answers (1)

Former Member
0 Kudos

I used the above code but ran into an additional problem: the font of the window was set to 'system', not the font set in SAP BO (tahoma in my case).

After some digging in the Windows API, I found that using createFont and SelectObject can be used to solve this. This led to yet another problem: finding out what font SAP BO is using.

I'm developing for BO 2007a, which stores the users font settings in C:\Documents and Settings\<user name>\Local Settings\Application Data\SAP\SAP Business One\b1-current-user.xml

I read this file, parsed the xml, and retrieved the font face name and font size.

Using the windows API you can convert the font size to a font height using the GetDeviceCaps function. This font height in combination with the font name can be used to create a font object using the CreateFont function (most parameters of this function can be set to their default values).

I then selected the font in the SAP window using the SelectObject function and retrieved the metrics using the method described above.

PS. The CreateFont, SelectObject and GetDeviceCaps functions can be exposed using DLLImport in a similar way as described above. I use C# so my code looks slightly different:



[DllImport("gdi32")] static extern int CreateFont(
          int nHeight,               // height of font
          int nWidth,                // average character width
          int nEscapement,           // angle of escapement
          int nOrientation,          // base-line orientation angle
          int fnWeight,              // font weight
          UInt32 fdwItalic,           // italic attribute option
          UInt32 fdwUnderline,        // underline attribute option
          UInt32 fdwStrikeOut,        // strikeout attribute option
          UInt32 fdwCharSet,          // character set identifier
          UInt32 fdwOutputPrecision,  // output precision
          UInt32 fdwClipPrecision,    // clipping precision
          UInt32 fdwQuality,          // output quality
          UInt32 fdwPitchAndFamily,   // pitch and family
          string lpszFace           // typeface name
        );
[DllImport("gdi32")] static extern int SelectObject(int hdc, int hgdiobj);
[DllImport("gdi32")] static extern int GetDeviceCaps(int hdc, int nIndex);