Embed custom font fot text box use in Visual Basic 2010

妖精的绣舞 提交于 2020-01-04 11:10:26

问题


OK I'm working on a problem tyring to embed a LCD type true type font in a text box. As for some background, I can get the lcd font to display if I install the font onto my system, then load it as the font type for the text box and it works great. However, it will not work as an embedded font in the application. I"m using a a Windows Forms Application in Visual Basic, from the Microsoft Visual Studio 2010 on a Windows 7 box.

I have tried the following code using a private font collection from memory after storing the font as a resource file and setting the property to embed resource.

Imports System.Drawing.Text

Imports System.Runtime.InteropServices

Module CustomFont

'PRIVATE FONT COLLECTION TO HOLD THE DYNAMIC FONT

Private _pfc As PrivateFontCollection = Nothing

Public ReadOnly Property GetInstance(ByVal Size As Single, _

                                     ByVal style As FontStyle) As Font

    Get

        'IF THIS IS THE FIRST TIME GETTING AN INSTANCE

        'LOAD THE FONT FROM RESOURCES

        If _pfc Is Nothing Then LoadFont()

        'RETURN A NEW FONT OBJECT BASED ON THE SIZE AND STYLE PASSED IN

        Return New Font(_pfc.Families(0), Size, style)


    End Get

End Property



Private Sub LoadFont()

    Try

        'INIT THE FONT COLLECTION

        _pfc = New PrivateFontCollection



        'LOAD MEMORY POINTER FOR FONT RESOURCE

        Dim fontMemPointer As IntPtr = _

            Marshal.AllocCoTaskMem( _

            My.Resources.DIGITALDREAMNARROW.Length)



        'COPY THE DATA TO THE MEMORY LOCATION

        Marshal.Copy(My.Resources.DIGITALDREAMNARROW, _

                     0, fontMemPointer, _

                     My.Resources.DIGITALDREAMNARROW.Length)



        'LOAD THE MEMORY FONT INTO THE PRIVATE FONT COLLECTION

        _pfc.AddMemoryFont(fontMemPointer, _

                           My.Resources.DIGITALDREAMNARROW.Length)


        'FREE UNSAFE MEMORY

        Marshal.FreeCoTaskMem(fontMemPointer)

    Catch ex As Exception

        'ERROR LOADING FONT. HANDLE EXCEPTION HERE

    End Try


End Sub

End Module

The problem with this code is that you are supposed to enable the control's UseCompatibleTextRendering property to true. Granted if using this module on a lable or button text it works great. For a text box however, there is no UseCompatibleTextRendering property.

I've come to understand that the text boxes use GDI rendering whereas the other text controls use GDI+ ( I may have those switched around, so don't quote me on that, All i remember is that they are different).

I found some older code snipits trying that use the AddFontMemResourceEX function from the gdi32.dll file in windows, and some have claimed that it works for use in text boxes. So I created the following class.

Imports System
Imports System.Drawing.Text
Imports System.IO
Imports System.Reflection

Public Class GetLCDFont
Private Declare Auto Function AddFontMemResourceEX Lib "gdi32.dll" _
    (ByVal pbFont As Integer, ByVal cbFont As Integer, _
     ByVal pdv As Integer, ByRef pcFonts As Integer) As IntPtr

Public Shared Function GetFont(ByVal fontName As String) As FontFamily

    Dim exeCurrent As [Assembly] = [Assembly].GetExecutingAssembly()
    Dim nameSpc As String = exeCurrent.GetName().Name.ToString()
    Dim fontCollection As New PrivateFontCollection
    Dim loadStream As Stream = exeCurrent.GetManifestResourceStream( _
        nameSpc + "." + fontName)
    Dim byteBuffer(CType(loadStream.Length, Integer)) As Byte

    loadStream.Read(byteBuffer, 0, Int(CType(loadStream.Length, Integer)))

    Dim fontPtr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal( _
        Runtime.InteropServices.Marshal.SizeOf(GetType(Byte)) * _
        byteBuffer.Length)

    Runtime.InteropServices.Marshal.Copy(byteBuffer, 0, fontPtr, byteBuffer.Length)

    fontCollection.AddMemoryFont(fontPtr, byteBuffer.Length)

    Dim pcFonts As Int32 = 1

    AddFontMemResourceEX(fontPtr, byteBuffer.Length, 0, pcFonts)

    Runtime.InteropServices.Marshal.FreeHGlobal(fontPtr)
    Return fontCollection.Families(0)

End Function

Public Sub New()

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub
End Class

However when calling this class, I get a InvalidOperatioException was unhandled. The error is Unable to find an entry pointed named 'AddFontMemResourceEX in DLL 'gdi32.dll'.

Hoping someone could help me either tell me what i'm going wrong, or point me in a direction that would help me embed a font for use in text boxes for use with a Windows Forms Application.

Most of the examples referenced at MSDN all point to how to package fonts when using a WPF application.

Thank you.


回答1:


I've been using the above code for labels, but never tried with a text box.

You could create a custom text box class that inherits from Textbox and then override the WndProc method, since the OnPaint won't render text.

Public Class CustomTextBox
  Inherits TextBox

  Public Const WM_NCPAINT As Integer = &H85

  <DllImport("User32.dll")> _
  Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
  End Function

  <DllImport("user32.dll")> _
  Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
  End Function

  Protected Overrides Sub WndProc(ByRef m As Message)
    MyBase.WndProc(m)

    If m.Msg = WM_NCPAINT Then
      Dim hDC As IntPtr = GetWindowDC(m.HWnd)
      Using g As Graphics = Graphics.FromHdc(hDC)
        g.DrawString(Me.Text, GetInstance(10, FontStyle.Bold), New SolidBrush(Me.ForeColor), Me.ClientRectangle)
      End Using
      ReleaseDC(m.HWnd, hDC)
    End If

  End Sub
End Class



回答2:


Although it's not as clean, you can use your installer to put the fonts in your application directory, and load them into your PrivateFontCollection using:

    For Each fontfile As String In System.IO.Directory.GetFiles(filepath & "\Fonts", "*.ttf")
        _pfc.AddFontFile(fontfile)
    Next fontfile

I'm not sure why Microsoft treats this differently, but my TextBoxes and ComboBoxes now use my custom fonts even though they don't have a UseCompatibleTextRendering property.



来源:https://stackoverflow.com/questions/15042199/embed-custom-font-fot-text-box-use-in-visual-basic-2010

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!